4.3.1 ResourceLoader接口
ResourceLoader接口用於返回Resource對象;其實現可以看作是一個生產Resource的工廠類。
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
getResource接口用於根據提供的location參數返回相應的Resource對象;而getClassLoader則返回加載這些Resource的ClassLoader。
Spring提供了一個適用於所有環境的DefaultResourceLoader實現,可以返回ClassPathResource、UrlResource;還提供一個用於web環境的ServletContextResourceLoader,它繼承了DefaultResourceLoader的所有功能,又額外提供了獲取ServletContextResource的支持。
ResourceLoader在進行加載資源時需要使用前綴來指定需要加載:“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource資源,如果不加前綴則需要根據當前上下文來決定,DefaultResourceLoader默認實現可以加載classpath資源,如代碼所示(cn.javass.spring.chapter4.ResourceLoaderTest):
@Test
public void testResourceLoad() {
ResourceLoader loader = new DefaultResourceLoader();
Resource resource = loader.getResource("classpath:cn/javass/spring/chapter4/test1.txt");
//驗證返回的是ClassPathResource
Assert.assertEquals(ClassPathResource.class, resource.getClass());
Resource resource2 = loader.getResource("file:cn/javass/spring/chapter4/test1.txt");
//驗證返回的是ClassPathResource
Assert.assertEquals(UrlResource.class, resource2.getClass());
Resource resource3 = loader.getResource("cn/javass/spring/chapter4/test1.txt");
//驗證返默認可以加載ClasspathResource
Assert.assertTrue(resource3 instanceof ClassPathResource);
}
對於目前所有ApplicationContext都實現了ResourceLoader,因此可以使用其來加載資源。
ClassPathXmlApplicationContext:不指定前綴將返回默認的ClassPathResource資源,否則將根據前綴來加載資源;
FileSystemXmlApplicationContext:不指定前綴將返回FileSystemResource,否則將根據前綴來加載資源;
WebApplicationContext:不指定前綴將返回ServletContextResource,否則將根據前綴來加載資源;
其他:不指定前綴根據當前上下文返回Resource實現,否則將根據前綴來加載資源。
4.3.2 ResourceLoaderAware接口
ResourceLoaderAware是一個標記接口,用於通過ApplicationContext上下文注入ResourceLoader。
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
讓我們看下測試代碼吧:
1) 首先准備測試Bean,我們的測試Bean還簡單只需實現ResourceLoaderAware接口,然后通過回調將ResourceLoader保存下來就可以了:
package cn.javass.spring.chapter4.bean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
public class ResourceBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}
2) 配置Bean定義(chapter4/resourceLoaderAware.xml):
<bean class="cn.javass.spring.chapter4.bean.ResourceBean"/>
3)測試(cn.javass.spring.chapter4.ResoureLoaderAwareTest):
@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter4/resourceLoaderAware.xml");
ResourceBean resourceBean = ctx.getBean(ResourceBean.class);
ResourceLoader loader = resourceBean.getResourceLoader();
Assert.assertTrue(loader instanceof ApplicationContext);
}
注意此處“loader instanceof ApplicationContext”,說明了ApplicationContext就是個ResoureLoader。
由於上述實現回調接口注入ResourceLoader的方式屬於侵入式,所以不推薦上述方法,可以采用更好的自動注入方式,如“byType”和“constructor”,此處就不演示了。
4.3.3 注入Resource
通過回調或注入方式注入“ResourceLoader”,然后再通過“ResourceLoader”再來加載需要的資源對於只需要加載某個固定的資源是不是很麻煩,有沒有更好的方法類似於前邊實例中注入“java.io.File”類似方式呢?
Spring提供了一個PropertyEditor “ResourceEditor”用於在注入的字符串和Resource之間進行轉換。因此可以使用注入方式注入Resource。
ResourceEditor完全使用ApplicationContext根據注入的路徑字符串獲取相應的Resource,說白了還是自己做還是容器幫你做的問題。
接下讓我們看下示例:
1)准備Bean:
package cn.javass.spring.chapter4.bean;
import org.springframework.core.io.Resource;
public class ResourceBean3 {
private Resource resource;
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
2)准備配置文件(chapter4/ resourceInject.xml):
<bean id="resourceBean1" class="cn.javass.spring.chapter4.bean.ResourceBean3"> <property name="resource" value="cn/javass/spring/chapter4/test1.properties"/> </bean> <bean id="resourceBean2" class="cn.javass.spring.chapter4.bean.ResourceBean3"> <property name="resource" value="classpath:cn/javass/spring/chapter4/test1.properties"/> </bean>
注意此處“resourceBean1”注入的路徑沒有前綴表示根據使用的ApplicationContext實現進行選擇Resource實現。
3)讓我們來看下測試代碼(cn.javass.spring.chapter4.ResourceInjectTest)吧:
@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter4/resourceInject.xml");
ResourceBean3 resourceBean1 = ctx.getBean("resourceBean1", ResourceBean3.class);
ResourceBean3 resourceBean2 = ctx.getBean("resourceBean2", ResourceBean3.class);
Assert.assertTrue(resourceBean1.getResource() instanceof ClassPathResource);
Assert.assertTrue(resourceBean2.getResource() instanceof ClassPathResource);
}
接下來一節讓我們深入ApplicationContext對各種Resource的支持,及如何使用更便利的資源加載方式。
