zoukankan      html  css  js  c++  java
  • spring中的ApplicationListener

    spring中的ApplicationListener是一个监听器,用来监听容器中发布的事件

    监听器也是一种观察者设计模式,该接口有一个onApplicationEvent()方法,

    在事件发布时,此方法将会调用,实现监听的功能。

    /**
     * Interface to be implemented by application event listeners.
     * Based on the standard {@code java.util.EventListener} interface
     * for the Observer design pattern.
     *
     * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
     * that it is interested in. When registered with a Spring ApplicationContext, events
     * will be filtered accordingly, with the listener getting invoked for matching event
     * objects only.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @param <E> the specific ApplicationEvent subclass to listen to
     * @see org.springframework.context.event.ApplicationEventMulticaster
     */
    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
        /**
         * Handle an application event.
         * @param event the event to respond to
         */
        void onApplicationEvent(E event);
    
    }

    自定义一个实现了ApplicationListener接口的实现类MyEventListener:

    @Component
    public class MyEventListener implements ApplicationListener<ApplicationEvent>{
    
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("监听到的事件发布。。。。。。。。。。"+event);
            }
    
    }

    配置类:

    @Configuration
    @Import({MyEventListener.class})
    public class ExtConfig {
    }

    测试类:

    public class ExtTest {
    
        @Test
        public void  test(){
            AnnotationConfigApplicationContext  applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
            applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {});
            applicationContext.close();
        }
    }

    打印结果:可以看到监听到了容器中三个事件的发布

    监听到的事件发布。。。。。。。。。。org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3339ad8e: 
    org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
    监听到的事件发布。。。。。。。。。。ExtTest$1[source=我发布的事件]
    信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3339ad8e:
    监听到的事件发布。。。。。。。。。。org.springframework.context.event.ContextClosedE

    发布流程:

    1》容器刷新完成事件ContextRefreshedEvent:

    refresh()--》finishRefresh()--》publishEvent(new ContextRefreshedEvent(this));

    2》自己发布的事件:

    publishEvent(event, null);

    3》容器关闭的事件ContextClosedEvent:

    close()-》doClose()-》publishEvent(new ContextClosedEvent(this));
    protected void publishEvent(Object event, ResolvableType eventType) {
            Assert.notNull(event, "Event must not be null");
            if (logger.isTraceEnabled()) {
                logger.trace("Publishing event in " + getDisplayName() + ": " + event);
            }
    
            // Decorate event as an ApplicationEvent if necessary
            ApplicationEvent applicationEvent;
            if (event instanceof ApplicationEvent) {
                applicationEvent = (ApplicationEvent) event;
            }
            else {
                applicationEvent = new PayloadApplicationEvent<Object>(this, event);
                if (eventType == null) {
                    eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
                }
            }
    
            // Multicast right now if possible - or lazily once the multicaster is initialized
            if (this.earlyApplicationEvents != null) {
                this.earlyApplicationEvents.add(applicationEvent);
            }
            else {
                getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
            }
    
            // Publish event via parent context as well...
            if (this.parent != null) {
                if (this.parent instanceof AbstractApplicationContext) {
                    ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
                }
                else {
                    this.parent.publishEvent(event);
                }
            }
        }
    执行getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);获取多波器(派发器)
    multicastEvent(applicationEvent, eventType):
    @Override
        public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
            ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
         //获取到所有的监听器,并遍历循环
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
          //获取执行器,并判断,有,异步执行
           Executor executor
    = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); }
            //没有就同步执行
    else { invokeListener(listener, event); } } }

    执行:doInvokeListener(listener, event)--》listener.onApplicationEvent(event);

        @SuppressWarnings({"unchecked", "rawtypes"})
        private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
            try {
                listener.onApplicationEvent(event);
            }
            catch (ClassCastException ex) {
                String msg = ex.getMessage();
                if (msg == null || msg.startsWith(event.getClass().getName())) {
                    // Possibly a lambda-defined listener which we could not resolve the generic event type for
                    Log logger = LogFactory.getLog(getClass());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Non-matching event type for listener: " + listener, ex);
                    }
                }
                else {
                    throw ex;
                }
            }
        }

     最终会去调用具体的onApplicationEvent()方法;

     getApplicationEventMulticaster()多播器(派发器)的获取:

    它是直接返回一个applicationEventMulticaster对象

    ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
            if (this.applicationEventMulticaster == null) {
                throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
                        "call 'refresh' before multicasting events via the context: " + this);
            }
            return this.applicationEventMulticaster;
        }

    在finishRefresh()前,有一个initApplicationEventMulticaster()初始化多播器的操作。

    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();

    initApplicationEventMulticaster():

    
    
    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";


    /**
    * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory();
          //先从beanFactory中判断是否有该bean,如果有就直接从beanFacotry中获取
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isDebugEnabled()) { logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else {
            //如果没有就自己创建一个SimpleApplocationEventMulticaster对象,它是
    ApplicationEventMulticaster的子类型
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            //并注册到beanFactory中,为单实例 beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
    this.applicationEventMulticaster); if (logger.isDebugEnabled()) { logger.debug("Unable to locate ApplicationEventMulticaster with name '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "': using default [" + this.applicationEventMulticaster + "]"); } } }

    还有另外一种实现监听机制的方法:使用@EventListener注解

    写一个UserService 

    @Service
    public class UserService {
    
        @EventListener(classes = {ApplicationEvent.class})
        public void listen(ApplicationEvent applicationEvent){
            System.out.println("applicationEvent...监听到的事件。。。"+applicationEvent);
        }
    }

    打印结果:

    UserService applicationEvent...监听到的事件。。。org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3339ad8e: startup date [Wed Dec 25 19:38:28 CST 2019]; root of context hierarchy]
    UserService applicationEvent...监听到的事件。。。ExtTest$1[source=我发布的事件]
    UserService applicationEvent...监听到的事件。。。org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3339ad8e: startup date [Wed Dec 25 19:38:28 CST 2019]; root of context hierarchy]

    EventListener 注解:

     * @author Stephane Nicoll
     * @since 4.2
     * @see EventListenerMethodProcessor
     */
    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EventListener {
    EventListenerMethodProcessor类:实现了SmartInitializingSingleton接口,并重写了afterSingletonsInstantiated()方法:
    public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {
    SmartInitializingSingleton 接口:它是在所有的bean实例都创建初始化后调用这个方法:
    public interface SmartInitializingSingleton {
    
        /**
         * Invoked right at the end of the singleton pre-instantiation phase,
         * with a guarantee that all regular singleton beans have been created
         * already. {@link ListableBeanFactory#getBeansOfType} calls within
         * this method won't trigger accidental side effects during bootstrap.
         * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
         * lazily initialized on demand after {@link BeanFactory} bootstrap,
         * and not for any other bean scope either. Carefully use it for beans
         * with the intended bootstrap semantics only.
         */
        void afterSingletonsInstantiated();
    
    }

    原理:

    ioc容器创建并refresh()——》》finishBeanFactoryInitialization(beanFactory)——》》beanFactory.preInstantiateSingletons()

    ——》》smartSingleton.afterSingletonsInstantiated();


    preInstantiateSingletons():
    @Override
        public void preInstantiateSingletons() throws BeansException {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Pre-instantiating singletons in " + this);
            }
    
            // Iterate over a copy to allow for init methods which in turn register new bean definitions.
            // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
            List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
          //创建并初始化所有的单实例bean
            // Trigger initialization of all non-lazy singleton beans...
            for (String beanName : beanNames) {
                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                    if (isFactoryBean(beanName)) {
                        final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                                @Override
                                public Boolean run() {
                                    return ((SmartFactoryBean<?>) factory).isEagerInit();
                                }
                            }, getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                    else {
                        getBean(beanName);
                    }
                }
            }
    
            // Trigger post-initialization callback for all applicable beans...
            for (String beanName : beanNames) {
                Object singletonInstance = getSingleton(beanName);
            //判断是否实现了该接口,是的话才回去调用这个方法
    if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }

    会调用EventListenerMethodProcessor的afterSingletonsInstantiated()
    @Override
        public void afterSingletonsInstantiated() {
            List<EventListenerFactory> factories = getEventListenerFactories();
            String[] beanNames = this.applicationContext.getBeanNamesForType(Object.class);
            for (String beanName : beanNames) {
                if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                    Class<?> type = null;
                    try {
                        type = AutoProxyUtils.determineTargetClass(this.applicationContext.getBeanFactory(), beanName);
                    }
                    catch (Throwable ex) {
                        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                        if (logger.isDebugEnabled()) {
                            logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                        }
                    }
                    if (type != null) {
                        if (ScopedObject.class.isAssignableFrom(type)) {
                            try {
                                type = AutoProxyUtils.determineTargetClass(this.applicationContext.getBeanFactory(),
                                        ScopedProxyUtils.getTargetBeanName(beanName));
                            }
                            catch (Throwable ex) {
                                // An invalid scoped proxy arrangement - let's ignore it.
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                                }
                            }
                        }
                        try {
                            processBean(factories, beanName, type);
                        }
                        catch (Throwable ex) {
                            throw new BeanInitializationException("Failed to process @EventListener " +
                                    "annotation on bean with name '" + beanName + "'", ex);
                        }
                    }
                }
            }
        }

    获取所有的 BeanFactory,找到其中标注了 @EventListener 的方法,
    利用反射和 DefaultEventListenerFactory 为其创建 ApplicationListener,并添加到事件派发器的缓存中。
     
  • 相关阅读:
    FHQ Treap(无旋 Treap)详解
    [CSP-S 2021] 廊桥分配 题解
    Splay Tree(伸展树)详解
    爬虫工程师也应该会的 NodeJS 知识(一)
    网站加密和混淆技术总结
    ip地址
    索引
    go try。。。catch
    python常见问题
    python实现发布订阅
  • 原文地址:https://www.cnblogs.com/tdyang/p/12093449.html
Copyright © 2011-2022 走看看