1. 程式人生 > 其它 >Spring:資源管理

Spring:資源管理

java 標準資源管理

職責 說明
面向資源 檔案系統、artifact(jar、war、ear檔案)以及遠端資源(HTTP、FTP等)
API整合 ClassLoader#getResource、java.io.File、java.net.URL
資源定位 java.net.URL、java.net.URI
面向流式儲存 java.net.URLConnection
協議擴充套件 java.net.URLStreamHandler 或 java.net.URLStreamHandlerFactory

基於java.net.URLStreamHandler擴充套件協議:jdk1.8內建協議實現,

自定義URLStreamHandler 物件,可以通過以下倆種方式注入到URL中:

  • 設定自定義的URLStreamHandler類名為Handler,然後在程式啟動的時候加上-Djava.protocol.handler.pkgs="Handler所在包名"引數,如果存在多個包名指定,可以通過分隔符"|"
  • 自定義java.net.URLStreamHandlerFactory ,然後通過URL#setURLStreamHandlerFactory設定

具體原理可參考:URL#getURLStreamHandler(String)方法原始碼

Spring資源管理介面

型別 介面
輸入流 org.springframework.core.io.InputStreamSource
只讀資源 org.springframework.core.io.Resource
可寫資源 org.springframework.core.io.WritableResource
編碼資源 org.springframework.core.io.support.EncodedResource
上下文資源 org.springframework.core.io.ContextResource

Spring資源載入器

下面列舉了三個常見的資源載入器實現,通過資源載入器載入對應的資源

測試:

public class FileSystemResourceLoaderDemo {

    public static void main(String[] args) throws IOException {
        String filePath = System.getProperty("user.dir") + "/spring-framework/spring-core/src/main/java/com/wj/resource/FileSystemResourceLoaderDemo.java";
        FileSystemResourceLoader resourceLoader = new FileSystemResourceLoader();
        Resource resource = resourceLoader.getResource(filePath);
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");

        Reader reader = encodedResource.getReader();
        System.out.println(FileCopyUtils.copyToString(reader));
    }
}

列印結果:

spring通配路徑資源載入器

通配路徑:

  • org.springframework.core.io.support.ResourcePatternResolver
    • org.springframework.core.io.support.PathMatchingResourcePatternResolver

路徑匹配器:

  • org.springframework.util.PathMatcher
    • Ant模式匹配:org.springframework.util.AntPathMatcher

可以通過通配路徑資源載入器獲取到所有匹配的資源

示例如下:獲取指定路徑下的所有java檔案

public class ResourcePatternResolverDemo {

    public static void main(String[] args) throws IOException {
        String filePath = System.getProperty("user.dir") + "/spring-framework/spring-core/src/main/java/com/wj/";
        String pattern = "**/*.java";

        PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(new FileSystemResourceLoader());

        Resource[] resources = patternResolver.getResources(filePath + pattern);

        for (Resource resource : resources) {
            System.out.println(resource.getFile().getName());
        }
    }

}

依賴注入Spring Resource

我在resource下面放了一個屬性配置檔案:

程式碼示例:

@Configuration
public class ResourceInjectDemo {

    @Value(ResourceUtils.CLASSPATH_URL_PREFIX + "resource.properties")
    private Resource resource;

    public Resource getResource() {
        return resource;
    }

    public static void main(String[] args) throws IOException {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ResourceInjectDemo.class);

        ResourceInjectDemo demo = applicationContext.getBean(ResourceInjectDemo.class);

        EncodedResource encodedResource = new EncodedResource(demo.getResource(), "UTF-8");
        Reader reader = encodedResource.getReader();
        System.out.println(FileCopyUtils.copyToString(reader));
    }

}

這裡通過@Value的形式就可以注入Resource物件到Bean中。

簡單說明一下原理,spring通過AutowiredAnnotationBeanPostProcessor後置處理器處理bean中的@Value註解,獲取到註解的value值,然後通過TypeConverter型別轉換器,實際上通過的是ResourceEditorString型別轉換成Resource,最後通過反射注入。

ResourceEditor中使用的就是ResourceLoader去載入Resource

此外,還可以注入陣列型別Resource

    @Value(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "*.properties")
    private Resource[] resources;

原理與前面類似,只不過最後型別轉換使用的是ResourceArrayPropertyEditor,而該類中使用的就是前面說到的PathMatchingResourcePatternResolver去路徑匹配,

關於型別轉換詳細原理可參考我前面的部落格:

ResourceLoader依賴注入

  • ResourceLoaderAware回撥
  • @Autowired注入ResourceLoader
  • 直接注入ApplicationContext,因為ApplicationContext實現了ResourceLoader

示例不就寫了,比較簡單。

原理解釋:

spring容器在啟動的時候,呼叫了prepareBeanFactory方法中,有這麼幾行:

這幾行說明 Spring在依賴注入的時候,當需要注入這四個型別的介面時,會把設定的指定物件注入進去,這裡ResourceLoader指定的物件就是ApplicationContext。

依賴注入的程式碼:

ResourceLoaderAware的原理就更簡單了:主要通過ApplicationContextAwareProcessor後置處理器進行設定,