桂林景区网站建设策划方案,做网站图片无法显示的原因,高端网站定制方案,昆明网站建设公司小程序EventListener注解详细使用
简介
EventListener是一种事件驱动编程在spring4.2的时候开始有的#xff0c;早期可以实现ApplicationListener接口, 为我们提供的一个事件监听、订阅的实现#xff0c;内部实现原理是观察者设计模式#xff1b;为的就是业务系统逻辑的解耦,提高…EventListener注解详细使用
简介
EventListener是一种事件驱动编程在spring4.2的时候开始有的早期可以实现ApplicationListener接口, 为我们提供的一个事件监听、订阅的实现内部实现原理是观察者设计模式为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听监听具体的实现内容是什么发布者的工作只是为了发布事件而已。比如我们做一个电商系统,用户下单支付成功后我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了把它解耦处理。
使用EventListener注解 建立事件对象当调用publishEvent方法是会通过这个bean对象找对应事件的监听。AddDataEvent.java package com.rw.article.pay.event.bean;import org.springframework.context.ApplicationEvent;/*** 新增mongodb数据事件*/
public class AddDataEvent extends ApplicationEvent {public AddDataEvent(Object source) {super(source);}public AddDataEvent(Object source, Class clz, Object data) {super(source);this.clz clz;this.data data;}public AddDataEvent(Object source, Class clz, Object data, String modelName, String userAgent) {super(source);this.clz clz;this.data data;this.modelName modelName;this.userAgent userAgent;}/** 要更新的表对象 **/private Class clz;/** 操作的数据**/private Object data;/** 模块名称**/private String modelName;/** 浏览器标识 **/private String userAgent;public Class getClz() {return clz;}public void setClz(Class clz) {this.clz clz;}public Object getData() {return data;}public void setData(Object data) {this.data data;}public String getModelName() {return modelName;}public void setModelName(String modelName) {this.modelName modelName;}public String getUserAgent() {return userAgent;}public void setUserAgent(String userAgent) {this.userAgent userAgent;}
} 对应的监听AddDataEventListener .java package com.rw.article.pay.event.listener;
import com.alibaba.fastjson.JSON;
import com.rw.article.pay.event.bean.AddDataEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;/*** 新增数据的事件监听*/
Component
public class AddDataEventListener {private static Logger log LoggerFactory.getLogger(AddDataEventListener.class);/** 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 AnnotationConfigUtils在AnnotationConfigServletWebServerApplicationContext构造方法里被加载* *//*** DefaultListableBeanFactory#中preInstantiateSingletons - (beanName为org.springframework.context.event.internalEventListenerProcessor时得到EventListenerMethodProcessor)EventListenerMethodProcessor#afterSingletonsInstantiated this.processBean(factories, beanName, type)* 然后把要执行的方法封装为ApplicationListenerMethodAdapter - 添加到listener中 AbstractApplicationEventMulticaster#addApplicationListener* */// 该方法在 ApplicationListenerMethodAdapter 利用反射执行/*** 处理新增数据的事件**/EventListenerpublic void handleAddEvent(AddDataEvent event) {log.info(发布的data为:{} , JSON.toJSONString(event));}
}建立测试类 package com.rw.article.pay.action;import com.rw.article.pay.event.bean.AddDataEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;/*** 测试的controller*/
Controller
RequestMapping(/test)
public class TestController {Resourceprivate ApplicationContext applicationContext;ResponseBodyRequestMapping(/testListener)public String testListener(){applicationContext.publishEvent(new AddDataEvent(this,TestController.class,test));return success;}
}结果是能够监听到的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHjkZeUm-1680567653256)(C:%5CUsers%5Cquyanliang%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1680567079331.png)] 如果要使用异步加上EnableAsync注解方法上加Async注解如下spring boot项目配置 SpringBootApplication
EnableAsync
public class XApplication{public static void main(String[] args) {ConfigurableApplicationContext run new SpringApplicationBuilder(XApplication.class).web(true).run(args);run.publishEvent(test);}
}AsyncEventListenerpublic void test(String wrapped){System.out.println(当前线程 Thread.currentThread().getName());System.out.println(wrapped);}还可以配置线程池taskExecutor Configuration
public class GenericConfiguration {Beanpublic Executor taskExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();//核心线程数线程池创建时候初始化的线程数//最大线程数线程池最大的线程数只有在缓冲队列满了之后才会申请超过核心线程数的线程//缓冲队列用来缓冲执行任务的队列//允许线程的空闲时间60秒当超过了核心线程出之外的线程在空闲时间到达之后会被销毁//线程池名的前缀设置好了之后可以方便我们定位处理任务所在的线程池//线程池对拒绝任务的处理策略这里采用了CallerRunsPolicy策略当线程池没有处理能力的时候该策略会直接在 execute 方法的调用线程中运行被拒绝的任务如果执行程序已关闭则会丢弃该任务executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(20);executor.setKeepAliveSeconds(60);executor.setThreadNamePrefix(taskExecutor-);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;}
}源码解析 原理还得从org.springframework.context.event.internalEventListenerProcessor 说起。 在AnnotationConfigUtils#registerAnnotationConfigProcessors注册了BeanDefinition 对应的是EventListenerMethodProcessor对象 而AnnotationConfigUtils是在AnnotationConfigServletWebServerApplicationContext构造方法里被加载。这里要提一下AnnotationConfigServletWebServerApplicationContext他是spring boot启动入口的重要类(我这里用的是spring boot所以是这个类),可以相当于以前用xml的ClassPathXmlApplicationContext。 public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME org.springframework.context.event.internalEventListenerProcessor;public static SetBeanDefinitionHolder registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Nullable Object source) {................... // 注册EventListenerMethodProcessor对象if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}...........................return beanDefs;}注册的EventListenerMethodProcessor对象会在初始化非懒加载对象的时候运行它的afterSingletonsInstantiated方法。 AbstractApplicationContext#finishBeanFactoryInitialization protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {............. // 初始化非懒加载对象beanFactory.preInstantiateSingletons();
}DefaultListableBeanFactory#preInstantiateSingletons Override
public void preInstantiateSingletons() throws BeansException {..................// 触发所有适用bean的初始化后回调 主要是afterSingletonsInstantiated方法for (String beanName : beanNames) {
//如果beanName传入org.springframework.context.event.internalEventListenerProcessor 因为已经上面代码已经初始化将从缓存中得到一个EventListenerMethodProcessor对象Object singletonInstance getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() ! null) {AccessController.doPrivileged((PrivilegedActionObject) () - {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {
// 调用其afterSingletonsInstantiated方法smartSingleton.afterSingletonsInstantiated();}}}
}EventListenerMethodProcessor#afterSingletonsInstantiated Override
public void afterSingletonsInstantiated() {ListEventListenerFactory factories getEventListenerFactories();ConfigurableApplicationContext context getApplicationContext();String[] beanNames context.getBeanNamesForType(Object.class);for (String beanName : beanNames) {if (!ScopedProxyUtils.isScopedTarget(beanName)) {Class? type null;try {type AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - lets 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 {Class? targetClass AutoProxyUtils.determineTargetClass(context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));if (targetClass ! null) {type targetClass;}}catch (Throwable ex) {// An invalid scoped proxy arrangement - lets ignore it.if (logger.isDebugEnabled()) {logger.debug(Could not resolve target bean for scoped proxy beanName , ex);}}}try {// 重点是这个方法 处理beanprocessBean(factories, beanName, type);}catch (Throwable ex) {throw new BeanInitializationException(Failed to process EventListener annotation on bean with name beanName , ex);}}}}
}EventListenerMethodProcessor#processBean;这里有一个重要的类就是ApplicationListenerMethodAdapter,spring把加入了EventListener注解的方法封装进ApplicationListenerMethodAdapter对象里,然后我们publishEvent方法是,其实是调用的对应的ApplicationListenerMethodAdapter,然后里面是执行这个方法,这里可以看下ApplicationListenerMethodAdapter类的属性。 public class ApplicationListenerMethodAdapter implements GenericApplicationListener {protected final Log logger LogFactory.getLog(getClass());private final String beanName;private final Method method;private final Method targetMethod;private final AnnotatedElementKey methodKey;private final ListResolvableType declaredEventTypes;Nullableprivate final String condition;private final int order;Nullableprivate ApplicationContext applicationContext;Nullableprivate EventExpressionEvaluator evaluator;..................................
}protected void processBean(final ListEventListenerFactory factories, final String beanName, final Class? targetType) {if (!this.nonAnnotatedClasses.contains(targetType)) {MapMethod, EventListener annotatedMethods null;try {// 拿到使用了EventListener注解的方法annotatedMethods MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookupEventListener) method -AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));}catch (Throwable ex) {// An unresolvable type in a method signature, probably from a lazy bean - lets 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 methodsConfigurableApplicationContext context getApplicationContext();for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {// 判断是否支持该方法 这里用的DefaultEventListenerFactory spring5.0.8 写死的返回trueif (factory.supportsMethod(method)) {//选择方法 beanName 这里是AddDataEventListener的beanName 默认是addDataEventListenerMethod methodToUse AopUtils.selectInvocableMethod(method, context.getType(beanName));// 这里是创建一个ApplicationListenerMethodAdapter对象ApplicationListener? applicationListener factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {// 如果是ApplicationListenerMethodAdapter对象 就把context和evaluator传进去((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}// 添加到ApplicationListener事件Set集合中去context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() EventListener methods processed on bean beanName : annotatedMethods);}}}
}后面就是触发事件监听了AbstractApplicationContext#publishEvent Override
public void publishEvent(ApplicationEvent event) {publishEvent(event, null);
}protected void publishEvent(Object event, Nullable ResolvableType eventType) {..............................// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents ! null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 进入multicastEventgetApplicationEventMulticaster().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);}}}SimpleApplicationEventMulticaster#multicastEvent-invokeListener-doInvokeListener private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);}catch (ClassCastException ex) {String msg ex.getMessage();if (msg null || matchesClassCastMessage(msg, event.getClass().getName())) {// Possibly a lambda-defined listener which we could not resolve the generic event type for// - lets suppress the exception and just log a debug message.Log logger LogFactory.getLog(getClass());if (logger.isDebugEnabled()) {logger.debug(Non-matching event type for listener: listener, ex);}}else {throw ex;}}
}ApplicationListenerMethodAdapter#onApplicationEvent] Override
public void onApplicationEvent(ApplicationEvent event) {processEvent(event);
}
ApplicationListenerMethodAdapter#processEventpublic void processEvent(ApplicationEvent event) {Object[] args resolveArguments(event);if (shouldHandle(event, args)) {// 执行真正的方法Object result doInvoke(args);if (result ! null) {handleResult(result);}else {logger.trace(No result object given - no result to handle);}}
}ApplicationListenerMethodAdapter#doInvoke protected Object doInvoke(Object... args) {Object bean getTargetBean();ReflectionUtils.makeAccessible(this.method);try {return this.method.invoke(bean, args);}catch (IllegalArgumentException ex) {assertTargetBean(this.method, bean, args);throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (IllegalAccessException ex) {throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (InvocationTargetException ex) {// Throw underlying exceptionThrowable targetException ex.getTargetException();if (targetException instanceof RuntimeException) {throw (RuntimeException) targetException;}else {String msg getInvocationErrorMessage(bean, Failed to invoke event listener method, args);throw new UndeclaredThrowableException(targetException, msg);}}
}ApplicationListenerMethodAdapter#getTargetBean protected Object getTargetBean() {Assert.notNull(this.applicationContext, ApplicationContext must no be null);return this.applicationContext.getBean(this.beanName);
}