博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring源码:ApplicationContext的增强功能(li)
阅读量:6177 次
发布时间:2019-06-21

本文共 3821 字,大约阅读时间需要 12 分钟。

              ApplicationContext作为资源加载器;ApplicationContext作为事件发布者;

  Java原生提供了事件发布机制------EventObject对象作为发布的事件,EventListener作为处理发布事件的监听器。但是其并没有提供发布者的角色来桥接EventObject和EventListener。Spring对java原生的事件发布机制做了扩展:一方面扩展了EventObject和EventListener,使其可以记录事件发布时间,扩展了事件发布接口;更重要的一点,ApplicationContext自身可以充当事件发布者(因为其实现了ApplicationEventPublisher接口),完成了本应该由开发者来实现的代码(如果使用java原生发布事件机制的话)。当对象A(被观察者)发生变化时,有一个发布者(可以是被观察者自身,也可以委托第三方如spring容器)发出通知,事物B(观察者)能够收到通知更新自己的状态。这个就是经常使用到的观察者模式,spring容器提供了这种观察者模式的支持。我们通过一个例子来说明如何在Spring框架中使用事件发布,并能让观察者(listener)得到消息。首先,自定义我们的EventObject,作为发布者和监听者之间约定好的事件对象。

public class MyEvent extends ApplicationEvent {     /**     *     */    private static final long serialVersionUID = 1L;     /**     * @param source     */    public MyEvent(Object source){        super(source);        // TODO Auto-generated constructor stub    } }

自定义的MyEvent继承了ApplicationEvent,ApplicationEvent类是spring框架继承EventObject而来,加入了获取发布时间的方法。其次,自定义我们的EventListener,它负责监听容器发布的ApplicationEvent事件并进行处理:

public class MyListener implements ApplicationListener {     /* (non-Javadoc)     * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)     */    @Override    public void onApplicationEvent(ApplicationEvent event) {        if (event instanceof MyEvent) {            System.out.println(event == null ? "" : event.getSource());        }    } }

因为我们只关心MyEvent事件的发布,所以在onApplicationEvent方法中进行了判断,过滤其他不相关发布事件。定义完了事件和监听器,基本就剩下发布事件的代码了。发布者由ApplicationContext来充当:

public class TestPublisher {    public static void main ( String args[] ) {        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // applicationContext.xml配置文件中已经配置好了监听器        ctx.publishEvent(new MyEvent("Hello World")); // 发布事件,监听器接收到事件消息    }}

最后,不要忘记在配置文件中添加监听对象:

spring容器会自动加载配置文件中所有的ApplicationListener对象,把它注册到观察者列表中。当有事件发布的时候,就从这个观察者列表中挨个通知事件发布。程序执行结果如下:

其他细节点:

  1. ApplicationContext自动加载所有的Bean ApplicationContext自动加载所有的Bean;
  2. ApplicationContext自动识别BeanFactoryPostProcessor,BeanPostProcessor,并注册到容器中。

  ApplicationContext自动加载所有的Bean:ApplicationContext相对于BeanFactory不同的一点是,BeanFactory在用到Bean的时候才会去加载bean(在beanFactory.getBean(“beanName”)之前不会加载beanName的对象)。而ApplicationContext不同,在容器创建时就已经把所有的Bean加载进容器了。

  ApplicationContext自动识别BeanFactoryPostProcessor,BeanPostProcessor,并注册到容器中:BeanFactoryPostProcessor是容器在加载完BeanDefinition之后,容器初始化之前对beanFactory做处理的一个扩展机制。比如我们的antx配置项替换类PropertyPlaceholderConfigurer。我们只需要在配置文件中声明PropertyPlaceholderConfigurer这类BeanFactoryPostProcessor对象,ApplicationContext就能够识别出来并自动将这些processor注册到容器中。BeanPostProcessor也是同样的道理,ApplicationContext能够自动识别xml中配置好的这类bean并进行容器的注册。BeanFactory就不能这么简洁了,必须我们手动去把那些BeanFactoryPostProcessor以及BeanPostProcessor对象注册到容器中。ApplicationContext能够自己感知到这些processor,我们的工作只是去实现自定义的(或者直接使用spring已经实现了的)BeanFactoryPostProcessor和BeanPostProcessor,并在配置文件中声明。是不是觉得很神奇?ApplicationContext能做到感知的原因就在于其对mdb(Merged BeanDefinition)的处理。

org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)实现: // Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// beanFactory的getBeanNamesForType方法能够根据对象的类型(此处是BeanFactoryPostProcessor.class),从mdb中找到他们的beanNameString[] postProcessorNames =        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);......// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.Collections.sort(priorityOrderedPostProcessors, new OrderComparator());// 这里所有声明在配置文件中的BeanFactoryPostProcessor都被调用,执行接口的postProcessBeanFactory方法。invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);

上面的代码中会从mdb中找出BeanFactoryPostProcessor接口的对象,并对它们进行排序,然后根据这些BeanFactoryPostProcessor依次对beanFactory处理。

转载地址:http://jbzda.baihongyu.com/

你可能感兴趣的文章
灾难恢复的人为因素:经理们应该做的10件事情
查看>>
中国教育行业可能到了最不平凡的10年:要么创新,要么死亡
查看>>
学习Docker的User Namespace
查看>>
Symantec Backup Exec 2012 Agent for Linux 卸载
查看>>
用EJB进行事务管理
查看>>
Linux Shell脚本系列之一
查看>>
数据可视化,个人经验总结(Echarts相关)
查看>>
Mysql MAC installation
查看>>
一款基于Vue和Go的桌面端管理star项目应用
查看>>
使用shell创建一个简单的菜单bash select用法
查看>>
Nuxt之默认模版和默认布局
查看>>
Vue模板、JS、CSS分离实现
查看>>
Hexo -- 快速、简洁且高效的博客框架 入门
查看>>
JVM
查看>>
高并发面试总结
查看>>
Pycharm--Python文件开头自动添加utf-8编码
查看>>
Leetcode PHP题解--D60 824. Goat Latin
查看>>
2019年一线大厂春招:Spring面试题和答案合集(上篇)
查看>>
尚未弄懂的JS系列(未完待续)
查看>>
浅析Java NIO
查看>>