zoukankan      html  css  js  c++  java
  • 详解Spring中的ApplicationListener和ContextRefreshedEvent

    ApplicationListener和ContextRefreshedEvent一般都是成对出现的。最近在面试中问到了被面试者对于这两个的用法,面试者大多数被问懵了。可见基础知识的掌握程度。基于此本文将介绍它们的用法。

    事件机制作为一种编程机制,在许多语言中都提供了支持。JAVA语言也不例外,java中的事件机制的参与者有3种角色:

    1. event object
    2. event source
    3. event listener

    这三个角色的含义字面上很好解,它们就定义了事件机制的一个基本模型。作为一种常用的编程设计机制,许多开源框架的设计中都使用了事件机制。SpringFramework也不例外。

    在IOC的容器的启动过程,当所有的bean都已经处理完成之后,spring ioc容器会有一个发布事件的动作。从 AbstractApplicationContext 的源码中就可以看出:

    protected void finishRefresh() {
        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();
        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();
        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));
        // 业余草:www.xttblog.com
        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }
    

    这样,当ioc容器加载处理完相应的bean之后,也给我们提供了一个机会(先有InitializingBean,后有ApplicationListener<ContextRefreshedEvent>),可以去做一些自己想做的事。其实这也就是spring ioc容器给提供的一个扩展的地方。我们可以这样使用这个扩展机制。

    org.springframework.context.ApplicationEvent
    org.springframework.context.ApplicationListener
    

     

    一个最简单的方式就是,让我们的bean实现ApplicationListener接口,这样当发布事件时,spring的ioc容器就会以容器的实例对象作为事件源类,并从中找到事件的监听者,此时ApplicationListener接口实例中的onApplicationEvent(E event)方法就会被调用,我们的逻辑代码就会写在此处。这样我们的目的就达到了。但这也带来一个思考,有人可能会想,这样的代码我们也可以通过实现spring的InitializingBean接口来实现啊,也会被spring容器去自动调用,但是大家应该想到,如果我们现在想做的事,是必须要等到所有的bean都被处理完成之后再进行,此时InitializingBean接口的实现就不合适了,所以需要深刻理解事件机制的应用场合。

    曾经有一位同事利用 ApplicationListener,重复加载了好几次 xml 配置文件。所以基础知识一定要掌握。

    下面是一个完整的例子:

    public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
        private static Logger _log = LoggerFactory.getLogger(ApplicationContextListener.class);
        @Override
        public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
            // root application context
            if(null == contextRefreshedEvent.getApplicationContext().getParent()) {
                _log.debug(">>>>> spring初始化完毕 <<<<<");
                // spring初始化完毕后,通过反射调用所有使用BaseService注解的initMapper方法
                Map<String, Object> baseServices =
                contextRefreshedEvent.getApplicationContext().getBeansWithAnnotation(BaseService.class);
                for(Object service : baseServices.values()) {
                    _log.debug(">>>>> {}.initMapper()", service.getClass().getName());
                    try {
                        Method initMapper = service.getClass().getMethod("initMapper");
                        initMapper.invoke(service);
                    } catch (Exception e) {
                        _log.error("初始化BaseService的initMapper方法异常", e);
                        e.printStackTrace();
                    }
                }
                // 系统入口初始化
                Map<String, BaseInterface> baseInterfaceBeans =
                contextRefreshedEvent.getApplicationContext().getBeansOfType(BaseInterface.class);
                for(Object service : baseInterfaceBeans.values()) {
                    _log.debug(">>>>> {}.init()", service.getClass().getName());
                    try {
                        Method init = service.getClass().getMethod("init");
                        init.invoke(service);
                    } catch (Exception e) {
                        _log.error("初始化BaseInterface的init方法异常", e);
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    以上就是ApplicationListener和ContextRefreshedEvent的相关用法。

  • 相关阅读:
    周末之个人杂想(十三)
    PowerTip of the DaySorting Multiple Properties
    PowerTip of the DayCreate Remoting Solutions
    PowerTip of the DayAdd Help to Your Functions
    PowerTip of the DayAcessing Function Parameters by Type
    PowerTip of the DayReplace Text in Files
    PowerTip of the DayAdding Extra Information
    PowerTip of the DayPrinting Results
    Win7下IIS 7.5配置SSAS(2008)远程访问
    PowerTip of the DayOpening Current Folder in Explorer
  • 原文地址:https://www.cnblogs.com/yuyu666/p/10071794.html
Copyright © 2011-2022 走看看