Spring 系列篇之ApplicationContext提供的其它能力

本篇文章主要介紹一下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集合對象)來添加PropertiesPropertySourceSystemEnvironmentPropertySource對象。下面這張圖是EnvironmentPropertysource的類關(guān)系圖。

Environment-PropertySource關(guān)系圖

ApplicationContext 其它功能

MessageSource

用于解析消息的接口,支持消息的參數(shù)化和格式化。


MessageSource類圖

MessageSourceResolvable & MessageSource

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

同樣我們可以用@AutowireMessageSourceAware方便獲取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());
    }
}
Spring event類圖

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)類圖

ResourceLoader

從圖中我們可以看到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ì)看看上面的類圖DefaultResourceLoaderPathMatchingResourcePatternResolver他們分別是對ResourceLoaderResourcePatternResolver實(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ù)更新!

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

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