美文网首页
Spring 系列篇之ApplicationContext提供的

Spring 系列篇之ApplicationContext提供的

作者: 雪狼_lykos | 来源:发表于2020-05-10 07:55 被阅读0次

    本篇文章主要介绍一下ApplicationContext的其它能力。Environment,PropertySourceMessageSource,Event,ResourceLoader
    [图片上传中...(image.png-46c0e-1589068396570-0)]

    Environment

    主要是为我们容器提供一个执行环境,可以控制哪些bean能够在哪些环境下(profiles)实例化,并包含对应的属性信息,这个特别适用于我们不同环境不同配置的使用场景。Spring在初始化容器时会默认创建Environment实例并注入进去,这里就用AnnotationConfigApplicationContext举例说明。当我们执行以下方法创建容器后

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(APP.class);
    

    Spring默认会创建StandardEnvironment对象注入到AbstractApplicationContext.environment属性中。我們可以通过Environment对象来获取当前的ActiveProfiles,而且Environment接口同时也继承了PropertyResolver接口,所以我们也可以通过其对象来获取当前属性信息
    那么在spring bean中我们可以用下面方式来获取

    使用@Autowired 自动装配

    @Autowired
    Environment environment;
    

    使用实现EnvironmentAware接口

    EnvironmentAware能够装配的原理是因为ApplicationContextAwareProcessor(实现了BeanPostProcessor接口)在其invokeAwareInterfaces()方法中执行了实例的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中默认有很多PropertySource实现类,如在创建StandardEnvironment对象时会默认使用MutablePropertySources(可以说是管理PropertySource集合对象)来添加PropertiesPropertySourceSystemEnvironmentPropertySource对象。下面这张图是EnvironmentPropertysource的类关系图。

    Environment-PropertySource关系图

    ApplicationContext 其它功能

    MessageSource

    用于解析消息的接口,支持消息的参数化和格式化。


    MessageSource类图
    MessageSourceResolvable & MessageSource

    Spring默认提供了多种实现,如ResourceBundleMessageSource,ReloadableResourceBundleMessageSource,DelegatingMessageSource
    默认情况下(我们没有手动配置/注册MessageSource对象)Spring在AbstractApplicationContext.initMessageSource中创建一个DelegatingMessageSource对象,他只是一个空的消息对象。如果我们需要提供国际化或者配置参数化消息,我们需要配置ReloadableResourceBundleMessageSource,如下:

        @Bean
        public ReloadableResourceBundleMessageSource messageSource(){
            ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
                    //这里i18n名字和配置文件一样
            reloadableResourceBundleMessageSource.setBasenames("i18n");
            reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
            return reloadableResourceBundleMessageSource;
        }
    

    ReloadableResourceBundleMessageSource默认会找我们setBasenames配置的文件并加载,这里我们可以按不同的语言以i18n_{Locale}创建我们需要国际化的配置,如:i18n_en.properties,i18n_zh.properties,i18n_zh_CN.properties

    i18n.properties

    默认配置,如果没有找到准备国际化配置,默认取此配置数据

    404=页面未找到Default
    

    i18n_ch.properties

    404=页面未找到
    

    i18n_en.properties

    404=page not found
    

    同样我们可以用@AutowireMessageSourceAware方便获取MessageSource,不仅如此我们还可以直接用ApplicationContext.getMessage解析消息

    Event

    Spring默认为我们实现了一套发布/订阅机制,我们首先需要了解的ApplicationEventMulticaster接口:可以管理多个ApplicationListener对象并向其发布事件的接口。Spring 在AbstractApplicationContext.initApplicationEventMulticaster中初始化applicationEventMulticaster(事件处理器),在此之前我们可以自己创建一个ApplicationEventMulticaster的实现对象(因为可以设置taskExecutor-异步处理,errorHandler-错误处理机制)来覆盖Spring默认为我们创建的SimpleApplicationEventMulticaster对象。

    事件发布

    创建事件

    我们发布的事件需要继承ApplicationEvent

    public class MyApplicationEvent extends ApplicationEvent {
        public MyApplicationEvent(Object source){
            super(source);
        }
    }
    

    发布事件

    发布事件需要获取事件发布器ApplicationEventPublisher,applicationEventPublisher通过publishEvent方法向applicationEventMulticaster发布ApplicationEvent消息。这里提供两种方法。第一种就是实现ApplicationEventPublisherAware接口,第一种就是获取到ApplicationContext对象,因为ApplicationContext接口也是继承了ApplicationEventPublisher。以下列举实现ApplicationEventPublisherAware接口

    @Component
    public class MyApplicationEventPublisher implements ApplicationEventPublisherAware {
        ApplicationEventPublisher applicationEventPublisher;
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.applicationEventPublisher = applicationEventPublisher;
        }
    }
    

    事件订阅

    订阅事件需要实现ApplicationListener接口,Spring利用ApplicationListenerDetector后置处理器向applicationEventMulticaster添加监听器,实现事件的订阅。

    @Component
    public class MyApplicationListener implements ApplicationListener {
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println(event.getClass());
        }
    }
    

    值得说明的是这里的MyApplicationListener是订阅了所有ApplicationEvent消息,其实我们也可以利用泛型指定订阅消息

    @Component
    public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
        @Override
        public void onApplicationEvent(MyApplicationEvent event) {
            System.out.println(event.getClass());
        }
    }
    
    Spring event类图

    ResourceLoader

    用于加载资源Resource的接口。

    Resource 接口旨在提供更加强大的功能用于抽象访问低级资源

    Spring 容器默认提供了API便于内部或者使用人员方便访问资源,资源包括classpath,file,https等。ResourceLoader接口定义如下

    public interface ResourceLoader {
        Resource getResource(String location);
        ClassLoader getClassLoader();
    }
    

    从接口定义上我们可以知道,ResourceLoader提供了getResource方法访问资源文件,参数是资源路径。我们先来看Spring对ResourceLoader实现类图

    ResourceLoader
    从图中我们可以看到ApplicationContext是继承了ResourceLoader接口,也就是说在Spring容器里ApplicationContext对象也是有getResource能力的。不仅如此,我们的ApplicaitonContext还继承了ResourcePatterResolver接口,意思是还可以通过通配符加载多个资源。因此当我们有加载资源的需求时我们可以通过ApplicationContext对象(实现ApplicationContextAware接口)或者ResourceLoader对象(实现ResourceLoaderAware接口)来获取资源文件。
    以下都是有效资源路径(不是全部)
    • classpath:com/myapp/config.xml classpath路径
      • classpath*:com/myapp/config.xml
      • classpath:com/myapp/.xml
      • classpath:com/*/config.xml
    • file:///data/config.xml 文件系统路径
      • file:///data/*.xml
    • http[s]://myserver/logo.png 网络路径
    • /data/config.xml 依赖于当前ApplicationContext
      • /data/*.xml

    注意:我们在仔细看看上面的类图DefaultResourceLoaderPathMatchingResourcePatternResolver他们分别是对ResourceLoaderResourcePatternResolver实现,记住他们是可以脱离容器独立使用的。下面是举例

    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"));
    }
    

    感谢

    感谢各位老铁花时间观看!
    欢迎留言指正!
    内容持续更新!

    相关文章

      网友评论

          本文标题:Spring 系列篇之ApplicationContext提供的

          本文链接:https://www.haomeiwen.com/subject/nalqmhtx.html