本篇文章主要介紹一下ApplicationContext的其它能力。Environment,PropertySource,MessageSource,Event,ResourceLoader
[圖片上傳中...(image.png-46c0e-1589068396570-0)]
Environment
主要是為我們?nèi)萜魈峁┮粋€(gè)執(zhí)行環(huán)境,可以控制哪些bean能夠在哪些環(huán)境下(profiles)實(shí)例化,并包含對應(yīng)的屬性信息,這個(gè)特別適用于我們不同環(huán)境不同配置的使用場景。Spring在初始化容器時(shí)會默認(rèn)創(chuàng)建Environment實(shí)例并注入進(jìn)去,這里就用AnnotationConfigApplicationContext舉例說明。當(dāng)我們執(zhí)行以下方法創(chuàng)建容器后
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(APP.class);
Spring默認(rèn)會創(chuàng)建StandardEnvironment對象注入到AbstractApplicationContext.environment屬性中。我們可以通過Environment對象來獲取當(dāng)前的ActiveProfiles,而且Environment接口同時(shí)也繼承了PropertyResolver接口,所以我們也可以通過其對象來獲取當(dāng)前屬性信息
那么在spring bean中我們可以用下面方式來獲取
使用@Autowired 自動裝配
@Autowired
Environment environment;
使用實(shí)現(xiàn)EnvironmentAware接口
EnvironmentAware能夠裝配的原理是因?yàn)?code>ApplicationContextAwareProcessor(實(shí)現(xiàn)了BeanPostProcessor接口)在其invokeAwareInterfaces()方法中執(zhí)行了實(shí)例的setEnvironment方法
@Component
public class MyEnvironmentAware implements EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
PropertySource
表示 key/value 屬性對 的抽象類。底層源對象可以是封裝屬性的任何T類型。如:java.util.Properties,java.util.Map,ServletContext和ServletConfig對象。在Spring中默認(rèn)有很多PropertySource實(shí)現(xiàn)類,如在創(chuàng)建StandardEnvironment對象時(shí)會默認(rèn)使用MutablePropertySources(可以說是管理PropertySource集合對象)來添加PropertiesPropertySource和SystemEnvironmentPropertySource對象。下面這張圖是Environment和Propertysource的類關(guān)系圖。

ApplicationContext 其它功能
MessageSource
用于解析消息的接口,支持消息的參數(shù)化和格式化。


Spring默認(rèn)提供了多種實(shí)現(xiàn),如ResourceBundleMessageSource,ReloadableResourceBundleMessageSource,DelegatingMessageSource。
默認(rèn)情況下(我們沒有手動配置/注冊MessageSource對象)Spring在AbstractApplicationContext.initMessageSource中創(chuàng)建一個(gè)DelegatingMessageSource對象,他只是一個(gè)空的消息對象。如果我們需要提供國際化或者配置參數(shù)化消息,我們需要配置ReloadableResourceBundleMessageSource,如下:
@Bean
public ReloadableResourceBundleMessageSource messageSource(){
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
//這里i18n名字和配置文件一樣
reloadableResourceBundleMessageSource.setBasenames("i18n");
reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
return reloadableResourceBundleMessageSource;
}
ReloadableResourceBundleMessageSource默認(rèn)會找我們setBasenames配置的文件并加載,這里我們可以按不同的語言以i18n_{Locale}創(chuàng)建我們需要國際化的配置,如:i18n_en.properties,i18n_zh.properties,i18n_zh_CN.properties等
i18n.properties
默認(rèn)配置,如果沒有找到準(zhǔn)備國際化配置,默認(rèn)取此配置數(shù)據(jù)
404=頁面未找到Default
i18n_ch.properties
404=頁面未找到
i18n_en.properties
404=page not found
同樣我們可以用@Autowire和MessageSourceAware方便獲取MessageSource,不僅如此我們還可以直接用ApplicationContext.getMessage解析消息
Event
Spring默認(rèn)為我們實(shí)現(xiàn)了一套發(fā)布/訂閱機(jī)制,我們首先需要了解的ApplicationEventMulticaster接口:可以管理多個(gè)ApplicationListener對象并向其發(fā)布事件的接口。Spring 在AbstractApplicationContext.initApplicationEventMulticaster中初始化applicationEventMulticaster(事件處理器),在此之前我們可以自己創(chuàng)建一個(gè)ApplicationEventMulticaster的實(shí)現(xiàn)對象(因?yàn)榭梢栽O(shè)置taskExecutor-異步處理,errorHandler-錯(cuò)誤處理機(jī)制)來覆蓋Spring默認(rèn)為我們創(chuàng)建的SimpleApplicationEventMulticaster對象。
事件發(fā)布
創(chuàng)建事件
我們發(fā)布的事件需要繼承ApplicationEvent。
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(Object source){
super(source);
}
}
發(fā)布事件
發(fā)布事件需要獲取事件發(fā)布器ApplicationEventPublisher,applicationEventPublisher通過publishEvent方法向applicationEventMulticaster發(fā)布ApplicationEvent消息。這里提供兩種方法。第一種就是實(shí)現(xiàn)ApplicationEventPublisherAware接口,第一種就是獲取到ApplicationContext對象,因?yàn)?code>ApplicationContext接口也是繼承了ApplicationEventPublisher。以下列舉實(shí)現(xiàn)ApplicationEventPublisherAware接口
@Component
public class MyApplicationEventPublisher implements ApplicationEventPublisherAware {
ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}
事件訂閱
訂閱事件需要實(shí)現(xiàn)ApplicationListener接口,Spring利用ApplicationListenerDetector后置處理器向applicationEventMulticaster添加監(jiān)聽器,實(shí)現(xiàn)事件的訂閱。
@Component
public class MyApplicationListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event.getClass());
}
}
值得說明的是這里的MyApplicationListener是訂閱了所有ApplicationEvent消息,其實(shí)我們也可以利用泛型指定訂閱消息
@Component
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println(event.getClass());
}
}

ResourceLoader
用于加載資源Resource的接口。
Resource 接口旨在提供更加強(qiáng)大的功能用于抽象訪問低級資源
Spring 容器默認(rèn)提供了API便于內(nèi)部或者使用人員方便訪問資源,資源包括classpath,file,https等。ResourceLoader接口定義如下
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
從接口定義上我們可以知道,ResourceLoader提供了getResource方法訪問資源文件,參數(shù)是資源路徑。我們先來看Spring對ResourceLoader實(shí)現(xiàn)類圖

從圖中我們可以看到
ApplicationContext是繼承了ResourceLoader接口,也就是說在Spring容器里ApplicationContext對象也是有getResource能力的。不僅如此,我們的ApplicaitonContext還繼承了ResourcePatterResolver接口,意思是還可以通過通配符加載多個(gè)資源。因此當(dāng)我們有加載資源的需求時(shí)我們可以通過ApplicationContext對象(實(shí)現(xiàn)ApplicationContextAware接口)或者ResourceLoader對象(實(shí)現(xiàn)ResourceLoaderAware接口)來獲取資源文件。以下都是有效資源路徑(不是全部)
- classpath:com/myapp/config.xml classpath路徑
- classpath*:com/myapp/config.xml
- classpath:com/myapp/.xml
- classpath:com/*/config.xml
- file:///data/config.xml 文件系統(tǒng)路徑
- file:///data/*.xml
- http[s]://myserver/logo.png 網(wǎng)絡(luò)路徑
- /data/config.xml 依賴于當(dāng)前ApplicationContext
- /data/*.xml
注意:我們在仔細(xì)看看上面的類圖DefaultResourceLoader和PathMatchingResourcePatternResolver他們分別是對ResourceLoader和ResourcePatternResolver實(shí)現(xiàn),記住他們是可以脫離容器獨(dú)立使用的。下面是舉例
DefaultResourceLoader 使用
DefaultResourceLoader defaultResourceLoader = new DefaultResourceLoader();
Resource resource = defaultResourceLoader.getResource("classpath:a.properties");
PathMatchingResourcePatternResolver 使用
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resourcePatternResolver.getResources("file:/Users/lykos/demo/*.properties");
for(Resource r : resources){
Properties properties = new Properties();
PropertiesLoaderUtils.fillProperties(properties, new EncodedResource(r,"utf-8"));
}
感謝
感謝各位老鐵花時(shí)間觀看!
歡迎留言指正!
內(nèi)容持續(xù)更新!