前言
ApplicationListener是spring为我们提供的基于事件驱动开发的功能,监听器可以监听容器中发布的事件,只要事件发生就触发监听器的回调来完成事件驱动开发。
/** * Interface to be implemented by application event listeners. * * <p>Based on the standard {@code java.util.EventListener} interface * for the Observer design pattern. * * <p>As of Spring 3.0, an {@code ApplicationListener} can generically declare * the event type that it is interested in. When registered with a Spring * {@code 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 {@code ApplicationEvent} subclass to listen to * @see org.springframework.context.ApplicationEvent * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.event.EventListener */ @FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
功能演示
可以通过实现ApplicationListener监听事件,也可以通过注解@EventListener让任意方法监听事件
//实现接口 ApplicationListener 监听事件
@Component public class MyApplicationListener implements ApplicationListener<ApplicationEvent> { //当容器中发布此事件以后,方法触发 @Override public void onApplicationEvent(ApplicationEvent event) { // TODO Auto-generated method stub System.out.println("=================>收到事件:"+event); } }
//通过注解让普通的业务逻辑方法监听事件
@Service public class UserService { @EventListener(classes={ApplicationEvent.class}) public void listen(ApplicationEvent event){ System.out.println("UserService。。===============》监听到的事件:"+event); } }
public class AOPTest { @Test public void testAop(){
//容器创建时触发对应的刷新事件 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class); /* Blue blue = applicationContext.getBean(Blue.class); System.out.println(blue);*/
//自定义发布事件; applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) { });
//关闭容器触发对应的关闭事件 applicationContext.close(); } }
原理分析
实现ApplicationListener接口监听事件调用栈及代码追踪
public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); register(componentClasses); refresh(); }
初始化ApplicationEventMulticaster;
1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
// 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(); }
// Publish the final event. publishEvent(new ContextRefreshedEvent(this));
//getApplicationEventMulticaster() 获取事件的多播器(派发器):
//multicastEvent派发事件:
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果有Executor,可以支持使用Executor进行异步派发; if (executor != null) { executor.execute(() -> invokeListener(listener, event)); }
//否则,同步的方式直接执行listener方法,拿到listener回调onApplicationEvent方法 else { invokeListener(listener, event); } } }
自定义事件的执行时机及容器关闭时关闭事件的触发与以上类似,不在分析
@EventListener原理分析
查看该注解对应的处理器
* alongside this event listener annotation. * * @author Stephane Nicoll * @author Sam Brannen * @since 4.2 * @see EventListenerMethodProcessor */ @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EventListener { /** * Alias for {@link #classes}. */ @AliasFor("classes") Class<?>[] value() default {}; /** * The event classes that this listener handles. * <p>If this attribute is specified with a single value, the * annotated method may optionally accept a single parameter. * However, if this attribute is specified with multiple values, * the annotated method must <em>not</em> declare any parameters. */ @AliasFor("value") Class<?>[] classes() default {}; /** * Spring Expression Language (SpEL) expression used for making the event * handling conditional. * <p>The event will be handled if the expression evaluates to boolean * {@code true} or one of the following strings: {@code "true"}, {@code "on"}, * {@code "yes"}, or {@code "1"}. * <p>The default expression is {@code ""}, meaning the event is always handled. * <p>The SpEL expression will be evaluated against a dedicated context that * provides the following metadata: * <ul> * <li>{@code #root.event} or {@code event} for references to the * {@link ApplicationEvent}</li> * <li>{@code #root.args} or {@code args} for references to the method * arguments array</li> * <li>Method arguments can be accessed by index. For example, the first * argument can be accessed via {@code #root.args[0]}, {@code args[0]}, * {@code #a0}, or {@code #p0}.</li> * <li>Method arguments can be accessed by name (with a preceding hash tag) * if parameter names are available in the compiled byte code.</li> * </ul> */ String condition() default ""; }
调用栈
/** * Finish the initialization of this context‘s bean factory, * initializing all remaining singleton beans. */ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }
@Override public void preInstantiateSingletons() throws BeansException { if (logger.isTraceEnabled()) { logger.trace("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<>(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)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((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);
//获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的; 如果是就调用afterSingletonsInstantiated(); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
常见事件及调用的时机
ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的事件]、ContextClosedEvent;
1)、ContextRefreshedEvent事件:
1)、容器创建对象:refresh();
2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
2)、自己发布事件 applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) { });;
3)、容器关闭会发布ContextClosedEvent;