(4)java的和spring的資源管理器的應用

1.java訪問資源的方式

比如現(xiàn)在有一個資源文件application.properties,現(xiàn)在要得到該配置文件的流,該文件放在resouces目錄下,文件內(nèi)容如下

spring.application.name = spring-resources

通過java方式的加載資源,打印輸出流

/**
 * @Project: spring
 * @description:  java 加載資源的方式
 * @author: sunkang
 * @create: 2018-09-23 22:16
 * @ModificationHistory who      when       What
 **/
public class FileLoadDemo {

    public static void main(String[] args) throws IOException {
        //1.用類加載器來實現(xiàn),不過這個是直接加載編譯好的classpath路勁的
        InputStream inputStream= FileLoadDemo.class.getClassLoader().getResourceAsStream("application.properties");
        System.out.println(inputStream);

        //2.通過絕對路勁的方式來加載
        File file = new File("");
        //file.getAbsolutePath() 得到的是user.dir,工作路徑,跟下面表示方法一樣
        System.out.println(System.getProperty("user.dir"));
        //spring-resources為一個模塊,所以這里需要加上模塊的路徑
        File resouceFile = new File("spring-resources/src/main/resources/application.properties");
        InputStream ins=  new BufferedInputStream(new FileInputStream(resouceFile));
        System.out.println(ins);

        //3通過nio加載
        InputStream nos= Files.newInputStream(Paths.get("spring-resources/src/main/resources/application.properties"));
        System.out.println(nos);

        //4 通過URL的方式
        URL fileURL = file.toURI().toURL();
        URLConnection urlConnection = fileURL.openConnection();
        InputStream inputStreamFromURL = urlConnection.getInputStream();
        System.out.println(inputStreamFromURL);
    }
}

這里面著重講解第四種方式
通過URL來定義資源的位置,該資源可以是文件,jar包,或者網(wǎng)絡資源。通過不同前綴名來代表每一種資源的協(xié)議,具體請求而的時候由不同的處理協(xié)議的handler進行處理
舉個例子:


/**
 * java 訪問資源可以通過URL這個對象來訪問各種資源,實際上URL為了得到inpustream需要以下的過程
*        URL -> URLConnection -> URLStreamHandler -> InputStream
*       這里用了委派模式,獲取inputStream會先要獲取URLConnection,而URLConnection是由URLStreamHandler創(chuàng)建而來
*       下面秒速了java支持的集中協(xié)議,可以rt.jar下在sun.net.www.protocol找到支持的協(xié)議模式
*      URL url = new URL("https://www.baidu.com"); // https 協(xié)議
*       URL ftpURL = new URL("ftp://ftp.baidu.com"); // ftp 協(xié)議
*       URL jar = new URL("jar://jar.baidu.com"); // jar 協(xié)議
*        file URLStreamHandler   = sun.net.www.protocol.file.Handler
*        http URLStreamHandler  =  sun.net.www.protocol.http.Handler
*        https URLStreamHandler  = sun.net.www.protocol.https.Handler
*        jar URLStreamHandler  = sun.net.www.protocol.jar.Handler
*        ftp URLStreamHandler  = sun.net.www.protocol.ftp.Handler
*        模式 URLStreamHandler =  sun.net.www.protocol.${protocol}.Handler
 *
 */
public class FileDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("spring-resources/src/main/resources/application.properties");
        URL fileURL = file.toURI().toURL();
        URLConnection urlConnection = fileURL.openConnection();
        InputStream inputStreamFromURL = urlConnection.getInputStream();
        //spring-core  核心包的工具類,把流的內(nèi)容轉成字符串
        String content = StreamUtils.copyToString(inputStreamFromURL, Charset.forName("UTF-8"));
        System.out.println(inputStreamFromURL);
    }
}

從下面的這個圖可以看出URL和其他接口的關系

image.png

在URL源碼部分中的getURLStreamHandler的方法中,存在如下的代碼段

if (handler == null) {
                String packagePrefixList = null;

                packagePrefixList
                    = java.security.AccessController.doPrivileged(
                    new sun.security.action.GetPropertyAction(
                        protocolPathProp,""));
                if (packagePrefixList != "") {
                    packagePrefixList += "|";
                }

                // REMIND: decide whether to allow the "null" class prefix
                // or not.
                packagePrefixList += "sun.net.www.protocol";

                StringTokenizer packagePrefixIter =
                    new StringTokenizer(packagePrefixList, "|");

                while (handler == null &&
                       packagePrefixIter.hasMoreTokens()) {

                    String packagePrefix =
                      packagePrefixIter.nextToken().trim();
                    try {
                        String clsName = packagePrefix + "." + protocol +
                          ".Handler";
                        Class<?> cls = null;
                        try {
                            cls = Class.forName(clsName);
                        } catch (ClassNotFoundException e) {
                            ClassLoader cl = ClassLoader.getSystemClassLoader();
                            if (cl != null) {
                                cls = cl.loadClass(clsName);
                            }
                        }
                        if (cls != null) {
                            handler  =
                              (URLStreamHandler)cls.newInstance();
                        }
                    } catch (Exception e) {
                        // any number of exceptions can get thrown here
                    }
                }
            }

基本上可以了解到是根據(jù) "sun.net.www.protocol" + 協(xié)議名稱+ ".handler" 得到一個類的全限定名,然后通過Class.forName(clsName)來得到類,如果出錯,則用引導類加載器來加載類,判斷cls不為空,cls.newInstance()用反射創(chuàng)建一個類

在java的sun.misc.Launcher有用到URLStreamHandlerFactory的工廠,ExtClassLoader和AppClassLoader的有用到這個URLStreamHandlerFactory工廠,有興趣的源碼可以研究下

2.拓展java的classpath路勁加載協(xié)議

要模仿創(chuàng)建一個類名為 sun.net.www.protocol.classpath.hanlder的類,該類如下:

/**
 * Classpath 協(xié)議 Handler
 *
 */
public class Handler extends URLStreamHandler {
    private final String PROTOCOL_PREFIX = "classpath:/";
    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        // 比如 url = "classpath:/META-INF/license.txt"
        // classpath  = META-INF/license.txt
        // 移除前綴 classpath:/
        // classpath:/META-INF/license.txt
        String urlString = url.toString();
        // META-INF/license.txt
        String classpath = urlString.substring(PROTOCOL_PREFIX.length());
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL classpathURL = classLoader.getResource(classpath);
        // 委派給 ClassLoader 實現(xiàn)
        return classpathURL.openConnection();
    }
}

測試類:

public class ClassPathUrlTest {
    public static void main(String[] args) throws IOException {
        URL url = new URL("classpath:/application.properties");
        URLConnection urlConnection = url.openConnection();

        InputStream inputStreamFromURL = urlConnection.getInputStream();

        String content = StreamUtils.copyToString(inputStreamFromURL,     Charset.forName("UTF-8"));

        System.out.println(content);
    }
}

測試結果如下:

spring.application.name = spring-resources

3.spring的加載方式 (DefaultResourceLoader)

/**
 * @Project: spring
 * @description:  spring 默認的加載資源的方式
 * @author: sunkang
 * @create: 2018-09-23 16:51
 * @ModificationHistory who      when       What
 **/
public class SprignResouceLoadTest {

    public static void main(String[] args) throws IOException {
//        ApplicationContext context = new ClassPathXmlApplicationContext();
//        context.getResource("application.properties")
        //ClassPathXmlApplicationContext繼承了DefaultResourceLoader,所以實際上DefaultResourceLoader在處理
        //用classPath
        //默認的加載器
        ResourceLoader recourceLoder = new DefaultResourceLoader();
        Resource resource =  recourceLoder.getResource("application.properties");
        InputStream ins= resource.getInputStream();
        System.out.println(ins);

        //加載 classpath路徑下的文件
        Resource classpathResource =  recourceLoder.getResource("classpath:application.properties");
        System.out.println(classpathResource.getInputStream());

        //通過file文件協(xié)議加載資源文件
        Resource fileResource =  recourceLoder.getResource("file:D:/Eclipse2018Data/personProject/spring/spring-resources/src/main/resources/application.properties");
        System.out.println(fileResource.getInputStream());

        //通過https協(xié)議加載資源文件
        Resource httpResource =  recourceLoder.getResource("https://start.spring.io/");
        System.out.println(fileResource.getInputStream());

    }
}

4.基于spring的拓展協(xié)議

/**
 * spring  拓展協(xié)議舉例
 *
 */
public class ResourceDemo {
    public static void main(String[] args) throws IOException {
        // Resource
        // FileSystemResource
        // ClasspathResource
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        // 添加一個protocol = "cp" 處理
        resourceLoader.addProtocolResolver(new ProtocolResolver() {
            private static final String PROTOCOL_PREFIX = "cp:/";
            @Override
            public Resource resolve(String location, ResourceLoader resourceLoader) {
                if (location.startsWith(PROTOCOL_PREFIX)) {
                    // application.properties
                    String classpath = ResourceLoader.CLASSPATH_URL_PREFIX +
                            location.substring(PROTOCOL_PREFIX.length());
                    // cp:/application.properties -> classpath:application.properties
                    return resourceLoader.getResource(classpath);
                }
                return null;
            }
        });
        Resource resource =
                resourceLoader.getResource("cp:/application.properties");

        InputStream inputStream = resource.getInputStream();
        String content = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8"));
        System.out.println(content);
    }
}

看DefaultResourceLoader的源碼可以了解到,先由添加的resourceLoader.addProtocolResolver()的協(xié)議一個個遍歷先解析,解析到了就返回,cp拓展的協(xié)議的實現(xiàn)是委派給了ClassPathResource去解析了

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評論 6 342
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,203評論 3 119
  • 我不想告別,卻不得不別, 我不知道用什么方式告別, 隔著玻璃模糊了我的視野, 多想夢回童年無憂的生活, 流逝的、經(jīng)...
    劉小地閱讀 312評論 3 19
  • 創(chuàng)新是一個民族進步的靈魂,一個沒有創(chuàng)新能力的民族,難以面對世界科技飛速發(fā)展的挑戰(zhàn),也無法屹立于世界民族之林。 如今...
    斗服腦閱讀 1,253評論 0 0

友情鏈接更多精彩內(nèi)容