当前位置: 首页 > news >正文

小红门网站建设惠州seo招聘

小红门网站建设,惠州seo招聘,iis网站建设中,上海58招聘网最新招聘EventListener注解详细使用 简介 EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高…

@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;@ResponseBody@RequestMapping("/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");}
    }
    
  •     @Async@EventListenerpublic 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 Set<BeanDefinitionHolder> 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((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {
    // 调用其afterSingletonsInstantiated方法smartSingleton.afterSingletonsInstantiated();}}}
    }
    
  • EventListenerMethodProcessor#afterSingletonsInstantiated

  •  @Override
    public void afterSingletonsInstantiated() {List<EventListenerFactory> 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 - 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 {Class<?> targetClass = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName));if (targetClass != null) {type = targetClass;}}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 {// 重点是这个方法 处理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 List<ResolvableType> declaredEventTypes;@Nullableprivate final String condition;private final int order;@Nullableprivate ApplicationContext applicationContext;@Nullableprivate EventExpressionEvaluator evaluator;..................................
    }
    
  • protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(targetType)) {Map<Method, EventListener> annotatedMethods = null;try {// 拿到使用了@EventListener注解的方法annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup<EventListener>) method ->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 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// -> let's 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);
    }
    
http://www.khdw.cn/news/28060.html

相关文章:

  • 增加网站关键词库关键词排名怎么上首页
  • 网站优化怎么做分录网络推广策划案
  • 用 asp net 做 的网站app拉新推广赚佣金
  • 做网站分什么软件宁波seo的公司联系方式
  • 网站卖东西怎么做的代运营
  • 上海这边敲墙拆旧做啥网站的比较多写一篇软文多少钱
  • 上海网站建设服方象科技专注于什么领域
  • 西安建设厅网站首页海南快速seo排名优化
  • 前几年做那些网站能致富百度精简版网页入口
  • 厚街镇做网站新网站如何快速收录
  • 做毕设的网站苏州网站优化公司
  • 做网站注意什么问题百度入口官网
  • 满屏网站做多大尺寸seo优化工具软件
  • 保定网站制作计划广告推广图片
  • 文化传播网站建设指数型基金
  • 加强网站建设和维护工作伊春seo
  • 北京市住房和城乡建设委员会官方网站的怎样在浏览器上找网站
  • 网站建设蓝图ppt微商怎么引流被别人加
  • 做订阅号要建立网站吗搜狗搜索引擎入口
  • 建瓯企业网站建设台州百度推广优化
  • 石家庄城市建设档案馆网站优化seo培训班
  • php网站开发 知乎站长工具网站推广
  • 赣州网站建设价格关键词优化的作用
  • 高手优化网站想要网站推广页
  • wordpress 管理员密码优化落实防控措施
  • 公众号做视频网站吗深圳广告公司排名
  • 吕子乔做网站吹的语录百度号码认证申诉平台
  • 装修公司经营范围武汉seo排名公司
  • 测评网站怎么做霸屏推广
  • 微信网站开发教程seo优化在线诊断