一、概念
1.事件监听的流程
步骤一、自定义事件,一般是继承ApplicationEvent抽象类
步骤二、定义事件监听器,一般是实现ApplicationListener接口
步骤三、启动时,需要将监听器加入到Spring容器中
步骤四、发布事件
对于配置监听器的方式【即第三步】
方式一、app.addListeners(new MyApplicationListener());添加监听器
方式二、把监听器使用纳入Spring配置中管理如使用@Component标注
方式三、再application.properties中添加context.listener.classes配置项配置
方式四、使用注解@EventListener在方法上,且该类需要在Spring上管理
2、示例【方式一】:
步骤一、自定义事件MyApplicationEvent
package com.lhx.spring.springboot_event; import org.springframework.context.ApplicationEvent; /** * 定义事件 * @author Administrator * */ public class MyApplicationEvent extends ApplicationEvent { private static final long serialVersionUID = 1L; public MyApplicationEvent(Object source) { super(source); } }
步骤二、定义事件监听器MyApplicationListener
package com.lhx.spring.springboot_event; import org.springframework.context.ApplicationListener; public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) { System.out.println("接收到事件:" + event.getClass()); } }
步骤三、在App启动程序中添加以及发布
@SpringBootApplication public class App { public static void main(String[] args) { // ConfigurableApplicationContext context = SpringApplication.run(App.class, // args); SpringApplication app = new SpringApplication(App.class); app.addListeners(new MyApplicationListener()); ConfigurableApplicationContext context = app.run(args); context.publishEvent(new MyApplicationEvent(new Object())); context.close(); } }
3、示例【方式二】:
注意:其实在示例步骤三,也可以用注解方式将时间监听器纳入Spring管理中
步骤一、与示例一一致
步骤二、将事件监听器添加@Component注解。
步骤三、启动类
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); //app.addListeners(new MyApplicationListener()); ConfigurableApplicationContext context = app.run(args); context.publishEvent(new MyApplicationEvent(new Object())); context.close(); } }
4、示例【方式四】:
步骤一、与示例一一致
步骤二、与示例一一致
步骤三、增加单独处理类
package com.lhx.spring.springboot_event; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyEventHandle { @EventListener public void event(MyApplicationEvent event) { System.out.println("MyEventHandle 接收到事件:" + event.getClass()); } @EventListener public void event2(ContextStoppedEvent event) { System.out.println("应用停止 接收到事件:" + event.getClass()); } }
步骤三、启动类
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class);、 ConfigurableApplicationContext context = app.run(args); context.publishEvent(new MyApplicationEvent(new Object())); context.close(); } }
二、配置监听器的方式原理
1.方式三实现,在application.properties中添加context.listener.classes配置项配置
查看:DelegatingApplicationListener
public class DelegatingApplicationListener implements ApplicationListener<ApplicationEvent>, Ordered { // NOTE: Similar to org.springframework.web.context.ContextLoader private static final String PROPERTY_NAME = "context.listener.classes";
核心逻辑
@Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { List<ApplicationListener<ApplicationEvent>> delegates = getListeners( ((ApplicationEnvironmentPreparedEvent) event).getEnvironment()); if (delegates.isEmpty()) { return; } this.multicaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<ApplicationEvent> listener : delegates) { this.multicaster.addApplicationListener(listener); } } if (this.multicaster != null) { this.multicaster.multicastEvent(event); } } @SuppressWarnings("unchecked") private List<ApplicationListener<ApplicationEvent>> getListeners( ConfigurableEnvironment environment) { if (environment == null) { return Collections.emptyList(); } String classNames = environment.getProperty(PROPERTY_NAME); List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>(); if (StringUtils.hasLength(classNames)) { for (String className : StringUtils.commaDelimitedListToSet(classNames)) { try { Class<?> clazz = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader()); Assert.isAssignable(ApplicationListener.class, clazz, "class [" + className + "] must implement ApplicationListener"); listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils .instantiateClass(clazz)); } catch (Exception ex) { throw new ApplicationContextException( "Failed to load context listener class [" + className + "]", ex); } } } AnnotationAwareOrderComparator.sort(listeners); return listeners; }
2、方式四实现
查看:EventListenerMethodProcessor的processBean
protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) { if (!this.nonAnnotatedClasses.contains(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { annotatedMethods = MethodIntrospector.selectMethods(targetType, new MethodIntrospector.MetadataLookup<EventListener>() { @Override public EventListener inspect(Method method) { return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class); } }); } catch (Throwable ex) { // An unresolvable type in a method signature, probably from a lazy bean - let‘s ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve methods for bean with name ‘" + beanName + "‘", ex); } } if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { logger.trace("No @EventListener annotations found on bean class: " + targetType.getName()); } } else { // Non-empty set of methods for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { Method methodToUse = AopUtils.selectInvocableMethod( method, this.applicationContext.getType(beanName)); ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener) .init(this.applicationContext, this.evaluator); } this.applicationContext.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean ‘" + beanName + "‘: " + annotatedMethods); } } } }
EventListener
annotatedMethods = MethodIntrospector.selectMethods(targetType, new MethodIntrospector.MetadataLookup<EventListener>() { @Override public EventListener inspect(Method method) { return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class); } });
查看for
for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { Method methodToUse = AopUtils.selectInvocableMethod( method, this.applicationContext.getType(beanName)); ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener) .init(this.applicationContext, this.evaluator); } this.applicationContext.addApplicationListener(applicationListener); break; } } }
其中factory即EventListenerFactory factory
/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.context.event; import java.lang.reflect.Method; import org.springframework.context.ApplicationListener; /** * Strategy interface for creating {@link ApplicationListener} for methods * annotated with {@link EventListener}. * * @author Stephane Nicoll * @since 4.2 */ public interface EventListenerFactory { /** * Specify if this factory supports the specified {@link Method}. * @param method an {@link EventListener} annotated method * @return {@code true} if this factory supports the specified method */ boolean supportsMethod(Method method); /** * Create an {@link ApplicationListener} for the specified method. * @param beanName the name of the bean * @param type the target type of the instance * @param method the {@link EventListener} annotated method * @return an application listener, suitable to invoke the specified method */ ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method); }
三、spring、Spring boot内置事件
1.Spring
jar包:Spring-context-4.3.13.RELEASE
包:org.springframwork.context.event;
常用:ContextClosedEvent、ContextStartedEvent、ContextStopedEvent
示例
@Component public class MyEventHandle { @EventListener public void event2(ContextStoppedEvent event) { System.out.println("应用停止 接收到事件:" + event.getClass()); } }
当然:app中Context要停止
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication app = new SpringApplication(App.class); ConfigurableApplicationContext context = app.run(args); context.publishEvent(new MyApplicationEvent(new Object())); context.stop(); } }
2.Spring-boot
jar包:Spring-boot-1.5.9.RELEASE
包:org.springframework.boot.context.event;
常用:ApplicationEnvironmentPreparedEvent、ApplicationFailedEvent等