经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring事件监听器之@EventListener原理分析
来源:jb51  时间:2021/12/31 10:41:13  对本文有异议

Spring事件监听器之@EventListener原理

Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。

在spring中我们可以通过实现ApplicationListener接口或者@EventListener接口来实现事件驱动编程

比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。

  1. public class OrderEvent extends ApplicationEvent {
  2. public OrderEvent(Object source) {
  3. super(source);
  4. }
  5. }
  6. @Component
  7. public class OrderEventListener {
  8. @EventListener
  9. public void listener(OrderEvent event) {
  10. System.out.println("i do OrderEventListener" );
  11. }
  12. }
  13. @Controller
  14. @RequestMapping("person")
  15. public class PersonController implements ApplicationContextAware {
  16. private ApplicationContext applicationContext;
  17. @Override
  18. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  19. this.applicationContext = applicationContext;
  20. }
  21. @ResponseBody
  22. @GetMapping("publishOrderEvent")
  23. public String publishOrderEvent() {
  24. applicationContext.publishEvent(new OrderEvent("我发布了事件!!!"));
  25. System.out.println(" publishOrderEvent ");
  26. return "发送事件了!";
  27. }
  28. }

EventListenerMethodProcessor是@EventListener的解析类,他是一个SmartInitializingSingleton和BeanFactoryPostProcessor

一、解析@EventListener前的准备工作

1.1 EventListenerFactory和EventListenerMethodProcessor的注入

EventListenerFactory是把@EventListener标注的方法变成ApplicationListener的关键,其是在容器最初期(refresh方法发生前)就放到容器中去

  1. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, Object source) {
  2. //获取对象
  3. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  4. //org.springframework.context.event.internalEventListenerProcessor
  5. //@EventListener注解处理器
  6. if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
  7. RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
  8. def.setSource(source);
  9. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  10. }
  11. //org.springframework.context.event.internalEventListenerProcessor
  12. //内部管理的EventListenerFactory的bean名称
  13. if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
  14. RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
  15. def.setSource(source);
  16. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  17. }
  18. return beanDefs;
  19. }
  • 如果容器中没有名字是org.springframework.context.event.internalEventListenerProcessor的bean,那么就注入一个EventListenerMethodProcessor到容器中
  • 如果容器中没有名字是org.springframework.context.event.internalEventListenerProcessor的bean,那么就注入一个DefaultEventListenerFactory到容器中

1.2 EventListenerMethodProcessor和EventListenerFactory关系的建立

EventListenerMethodProcessor会在容器启动时被注入到容器中,他是一个BeanFactoryPostProcessor,EventListenerMethodProcessor和EventListenerFactory关系的建立就发生在其方法postProcessBeanFactory中

  1. public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
  2. @Nullable
  3. private List<EventListenerFactory> eventListenerFactories;
  4. //初始化eventListenerFactories
  5. @Override
  6. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  7. this.beanFactory = beanFactory;
  8. //获取容器中所有的EventListenerFactory,并把他们实例化
  9. Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
  10. List<EventListenerFactory> factories = new ArrayList<>(beans.values());
  11. AnnotationAwareOrderComparator.sort(factories);
  12. //将EventListenerFactory储存到缓存eventListenerFactories中,便于后来使用
  13. this.eventListenerFactories = factories;
  14. }
  15. }

EventListenerFactory的实例化时机只比BeanFactoryPostProcessor完点,他比BeanPostProcessor实例化时机早

二、开始解析@EventListener

EventListenerMethodProcessor是一个SmartInitializingSingleton,所以他会在所以bean实例化后,执行其afterSingletonsInstantiated方法

注意:只有单例的SmartInitializingSingleton,才会执行其afterSingletonsInstantiated方法

2.1 基本流程

  1. public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
  2. @Override
  3. public void afterSingletonsInstantiated() {
  4. ConfigurableListableBeanFactory beanFactory = this.beanFactory;
  5. Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
  6. // 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~ 一个一个的检查
  7. String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
  8. for (String beanName : beanNames) {
  9. //
  10. if (!ScopedProxyUtils.isScopedTarget(beanName)) {
  11. Class<?> type = null;
  12. try {
  13. // 防止是代理,吧真实的类型拿出来
  14. type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
  15. }
  16. catch (Throwable ex) {
  17. if (logger.isDebugEnabled()) {
  18. logger.debug("", ex);
  19. }
  20. }
  21. if (type != null) {
  22. // 对专门的作用域对象进行兼容~~~~(绝大部分都用不着)
  23. if (ScopedObject.class.isAssignableFrom(type)) {
  24. try {
  25. Class<?> targetClass = AutoProxyUtils.determineTargetClass(
  26. beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
  27. if (targetClass != null) {
  28. type = targetClass;
  29. }
  30. }
  31. catch (Throwable ex) {
  32. // An invalid scoped proxy arrangement - let's ignore it.
  33. if (logger.isDebugEnabled()) {
  34. logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
  35. }
  36. }
  37. }
  38. try {
  39. // 真正处理这个Bean里面的方法们。。。
  40. processBean(beanName, type);
  41. }
  42. catch (Throwable ex) {
  43. throw new BeanInitializationException("", ex);
  44. }
  45. }
  46. }
  47. }
  48. }
  49. private void processBean(final String beanName, final Class<?> targetType) {
  50. //类上有@Component注解
  51. if (!this.nonAnnotatedClasses.contains(targetType) &&!targetType.getName().startsWith("java") &&!isSpringContainerClass(targetType)) {
  52. Map<Method, EventListener> annotatedMethods = null;
  53. try {
  54. //获取类中用@EventListener标注方法的信息
  55. annotatedMethods = MethodIntrospector.selectMethods(targetType,
  56. (MethodIntrospector.MetadataLookup<EventListener>) method ->
  57. AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
  58. }
  59. catch (Throwable ex) {
  60. // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
  61. if (logger.isDebugEnabled()) {
  62. logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
  63. }
  64. }
  65. //如果annotatedMethods为空,那代表类中没有用@EventListener标注的方法
  66. if (CollectionUtils.isEmpty(annotatedMethods)) {
  67. this.nonAnnotatedClasses.add(targetType);
  68. if (logger.isTraceEnabled()) {
  69. logger.trace("" + targetType.getName());
  70. }
  71. }
  72. else {
  73. // 类中存在用@EventListener标注的方法
  74. ConfigurableApplicationContext context = this.applicationContext;
  75. Assert.state(context != null, "No ApplicationContext set");
  76. //获取容器中所有EventListenerFactory
  77. List<EventListenerFactory> factories = this.eventListenerFactories;
  78. Assert.state(factories != null, "EventListenerFactory List not initialized");
  79. for (Method method : annotatedMethods.keySet()) {
  80. for (EventListenerFactory factory : factories) {
  81. if (factory.supportsMethod(method)) {
  82. // 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关)
  83. // 这里注意:若你是JDK的代理类,请不要在实现类里书写@EventListener注解的监听器,否则会报错的。(CGLIB代理的木关系)
  84. Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
  85. //利用EventListenerFactory创建ApplicationListener,详情后面说
  86. ApplicationListener<?> applicationListener =
  87. factory.createApplicationListener(beanName, targetType, methodToUse);
  88. //如果ApplicationListener是ApplicationListenerMethodAdapter类,那么执行其init方法
  89. if (applicationListener instanceof ApplicationListenerMethodAdapter) {
  90. ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
  91. }
  92. //放到容器中
  93. context.addApplicationListener(applicationListener);
  94. //@EventListener方法只能解析一次
  95. break;
  96. }
  97. }
  98. }
  99. if (logger.isDebugEnabled()) {
  100. logger.debug();
  101. }
  102. }
  103. }
  104. }
  105. }

获取容器中所有的类,把用@Component标注的类上所有的@EventListener方法用EventListenerFactory解析成一个ApplicationListener

@EventListener方法只要有到一个可以解析他的EventListenerFactory,就不会让其他EventListenerFactory解析他了 所以如果容器中存在多个EventListenerFactory,我要注意他的顺序

2.2 EventListenerFactory解析@EventListener

在这里插入图片描述

  1. public interface EventListenerFactory {
  2. //是否支持当前方法
  3. boolean supportsMethod(Method method);
  4. //生成一个ApplicationListener
  5. ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);
  6. }

EventListenerFactory有2个字类DefaultEventListenerFactory和TransactionalEventListenerFactory,DefaultEventListenerFactory是处理@EventListener,而TransactionalEventListenerFactory是处理@TransactionalEventListener的,Spring默认就有DefaultEventListenerFactory,而TransactionalEventListenerFactory是没有的,所以我们想要支持@TransactionalEventListener,就要注册一个TransactionalEventListenerFactory,也就是要说要使用@EnableTransactionManagement注解

  1. public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
  2. private int order = LOWEST_PRECEDENCE;
  3. @Override
  4. public boolean supportsMethod(Method method) {
  5. return true;
  6. }
  7. @Override
  8. public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
  9. return new ApplicationListenerMethodAdapter(beanName, type, method);
  10. }
  11. }

ApplicationListenerMethodAdapter一个ApplicationListener,他是用来包装@EventListener标注的方法

  1. public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
  2. private final String beanName; //@EventListener方法所属bean的名字
  3. private final Method method;//@EventListener标注的方法
  4. private final Method targetMethod;//@EventListener标注的真实方法对象,防止其是代理方法
  5. //方法申明,如public void demo.Ball.applicationContextEvent(demo.OrderEvent)
  6. private final AnnotatedElementKey methodKey;
  7. private final List<ResolvableType> declaredEventTypes;//存储方法的参数
  8. private final String condition;//@EventListener的condition
  9. private final int order;
  10. private ApplicationContext applicationContext;
  11. private EventExpressionEvaluator evaluator;//@EventListener的EventExpressionEvaluator
  12. public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
  13. this.beanName = beanName;
  14. this.method = BridgeMethodResolver.findBridgedMethod(method);
  15. this.targetMethod = (!Proxy.isProxyClass(targetClass) ?AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
  16. this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
  17. //获取方法上的@EventListener注解对象
  18. EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
  19. this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
  20. this.condition = (ann != null ? ann.condition() : null);
  21. this.order = resolveOrder(this.targetMethod);
  22. }
  23. public void onApplicationEvent(ApplicationEvent event) {
  24. processEvent(event);
  25. }
  26. public void processEvent(ApplicationEvent event) {
  27. Object[] args = resolveArguments(event);
  28. //根据@EventListener的condition,判断是否要处理
  29. if (shouldHandle(event, args)) {
  30. //调用方法
  31. Object result = doInvoke(args);
  32. if (result != null) {
  33. //如果有监听器可以监听这个结果,那么可以触发那个监听器
  34. handleResult(result);
  35. }
  36. else {
  37. logger.trace("No result object given - no result to handle");
  38. }
  39. }
  40. }
  41. }

EventListener.Factory

EventListener.Factory监听网络请求全过程

网上介绍的并不多,关于它的使用方式,可能会存在很多坑。

主要是为了监听网络请求过程。

首先OkHttpClient.Builder.eventListenerFactory需要的是一个实现了EventListener接口的工厂类。

简单的实现方式。

  1. public class HttpEventListener extends EventListener {
  2. private final long callId;
  3. final AtomicLong nextCallId = new AtomicLong(1L);
  4. @Override
  5. public EventListener create(Call call) {
  6. long callId = nextCallId.getAndIncrement();
  7. return new HttpEventListener(callId, System.nanoTime());
  8. }
  9. public HttpEventListener(long callId, long callStartNanos) {
  10. this.callId = callId;
  11. this.callStartNanos = callStartNanos;
  12. }
  13. private long dnsStartTime;
  14. private long dnsParseTime;
  15. @Override
  16. public void dnsStart(Call call, String domainName) {
  17. super.dnsStart(call, domainName);
  18. dnsStartTime = System.nanoTime();
  19. }
  20. @Override
  21. public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
  22. super.dnsEnd(call, domainName, inetAddressList);
  23. dnsParseTime = System.nanoTime() - dnsStartTime;//dns解析耗时
  24. }
  25. //自动补全剩余实现方法
  26. }

EventListener.create方法在okHttpClient.newCall后执行

dnsParseTime可以算出dns解析耗时,还可以监听每次dns解析的domain,解析的结果inetAddressList。

这个是比较好用的。

问题是如何将这些数据回传回来呢

在OkHttpClient构造时传入自定义参数

  1. OkHttpClient.Builder builder = new OkHttpClient.Builder();
  2. final ResponseTag tag = new ResponseTag();
  3. tag.logHandler = logHandler;
  4. httpClient.newCall(requestBuilder.tag(tag).build()).enqueue(new Callback() {
  5. @Override
  6. public void onFailure(Call call, IOException e) {
  7. }
  8. @Override
  9. public void onResponse(Call call, Response response) throws IOException {
  10. }
  11. });
  12. //自动补全剩余实现方法
  13. public class HttpEventListener extends EventListener {
  14. /**
  15. * 每次请求的标识
  16. */
  17. private long callId = 1L;
  18. /**
  19. * 每次请求的开始时间,单位纳秒
  20. */
  21. private final long callStartNanos;
  22. private long total_elapsed_time;
  23. private long dns_elapsed_time;
  24. private long connect_elapsed_time;
  25. private long tls_connect_elapsed_time;
  26. private long request_elapsed_time;
  27. private long wait_elapsed_time;
  28. private long response_elapsed_time;
  29. private Client.ResponseTag responseTag;
  30. private LogHandler logHandler;
  31. private long start_dns_elapsed_time;
  32. private long start_total_elapsed_time;
  33. private long start_connect_elapsed_time;
  34. private long start_tls_connect_elapsed_time;
  35. private long start_request_elapsed_time;
  36. private long start_response_elapsed_time;
  37. public HttpEventListener(long callId, Client.ResponseTag responseTag, long callStartNanos) {
  38. this.callId = callId;
  39. this.callStartNanos = callStartNanos;
  40. this.responseTag = responseTag;
  41. this.logHandler = responseTag.logHandler;
  42. }
  43. public static final Factory FACTORY = new Factory() {
  44. final AtomicLong nextCallId = new AtomicLong(1L);
  45. @Override
  46. public EventListener create(@NotNull Call call) {
  47. long callId = nextCallId.getAndIncrement();
  48. return new HttpEventListener(callId, (Client.ResponseTag) call.request().tag(), System.nanoTime());
  49. }
  50. };
  51. @Override
  52. public void callStart(Call call) {
  53. super.callStart(call);
  54. start_total_elapsed_time = System.currentTimeMillis();
  55. }
  56. @Override
  57. public void dnsStart(Call call, String domainName) {
  58. super.dnsStart(call, domainName);
  59. start_dns_elapsed_time = System.currentTimeMillis();
  60. }
  61. @Override
  62. public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
  63. super.dnsEnd(call, domainName, inetAddressList);
  64. dns_elapsed_time = System.currentTimeMillis() - start_dns_elapsed_time;//dns解析耗时
  65. logHandler.send("dns_elapsed_time", dns_elapsed_time);
  66. }
  67. @Override
  68. public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
  69. super.connectStart(call, inetSocketAddress, proxy);
  70. start_connect_elapsed_time = System.currentTimeMillis();
  71. }
  72. @Override
  73. public void secureConnectStart(Call call) {
  74. super.secureConnectStart(call);
  75. start_tls_connect_elapsed_time = System.currentTimeMillis();
  76. }
  77. @Override
  78. public void secureConnectEnd(Call call, Handshake handshake) {
  79. super.secureConnectEnd(call, handshake);
  80. tls_connect_elapsed_time = System.currentTimeMillis() - start_tls_connect_elapsed_time;
  81. logHandler.send("tls_connect_elapsed_time", tls_connect_elapsed_time);
  82. }
  83. @Override
  84. public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) {
  85. super.connectEnd(call, inetSocketAddress, proxy, protocol);
  86. connect_elapsed_time = System.currentTimeMillis() - start_connect_elapsed_time;
  87. logHandler.send("connect_elapsed_time", connect_elapsed_time);
  88. }
  89. @Override
  90. public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {
  91. super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
  92. }
  93. @Override
  94. public void connectionAcquired(Call call, Connection connection) {
  95. super.connectionAcquired(call, connection);
  96. }
  97. @Override
  98. public void connectionReleased(Call call, Connection connection) {
  99. super.connectionReleased(call, connection);
  100. }
  101. @Override
  102. public void requestHeadersStart(Call call) {
  103. super.requestHeadersStart(call);
  104. start_request_elapsed_time = System.currentTimeMillis();
  105. }
  106. @Override
  107. public void requestHeadersEnd(Call call, Request request) {
  108. super.requestHeadersEnd(call, request);
  109. }
  110. @Override
  111. public void requestBodyStart(Call call) {
  112. super.requestBodyStart(call);
  113. }
  114. @Override
  115. public void requestBodyEnd(Call call, long byteCount) {
  116. super.requestBodyEnd(call, byteCount);
  117. request_elapsed_time = System.currentTimeMillis() - start_request_elapsed_time;
  118. logHandler.send("request_elapsed_time", request_elapsed_time);
  119. }
  120. @Override
  121. public void responseHeadersStart(Call call) {
  122. super.responseHeadersStart(call);
  123. start_response_elapsed_time = System.currentTimeMillis();
  124. }
  125. @Override
  126. public void responseHeadersEnd(Call call, Response response) {
  127. super.responseHeadersEnd(call, response);
  128. }
  129. @Override
  130. public void responseBodyStart(Call call) {
  131. super.responseBodyStart(call);
  132. }
  133. @Override
  134. public void responseBodyEnd(Call call, long byteCount) {
  135. super.responseBodyEnd(call, byteCount);
  136. response_elapsed_time = System.currentTimeMillis() - start_response_elapsed_time;
  137. wait_elapsed_time = System.currentTimeMillis() - start_request_elapsed_time;
  138. logHandler.send("response_elapsed_time", response_elapsed_time);
  139. logHandler.send("wait_elapsed_time", wait_elapsed_time);
  140. }
  141. @Override
  142. public void callEnd(Call call) {
  143. super.callEnd(call);
  144. total_elapsed_time = System.currentTimeMillis() - start_total_elapsed_time;
  145. logHandler.send("total_elapsed_time", total_elapsed_time);
  146. }
  147. @Override
  148. public void callFailed(Call call, IOException ioe) {
  149. super.callFailed(call, ioe);
  150. }
  151. }
  152. //利用反射将logHandler打回来的数据存到对象
  153. public static LogHandler getUplogHandler(final Object obj) {
  154. final String setMethod = "set";
  155. LogHandler logHandler = new LogHandler() {
  156. @Override
  157. public void send(String key, Object value) {
  158. try {
  159. if (value instanceof String) {
  160. Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), Class.forName("java.lang.String"));
  161. setByKey.invoke(obj, value);
  162. } else if (value instanceof Integer) {
  163. Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), int.class);
  164. setByKey.invoke(obj, value);
  165. } else if (value instanceof Long) {
  166. Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), long.class);
  167. setByKey.invoke(obj, value);
  168. }
  169. } catch (NoSuchMethodException e) {
  170. e.printStackTrace();
  171. } catch (IllegalAccessException e) {
  172. e.printStackTrace();
  173. } catch (InvocationTargetException e) {
  174. e.printStackTrace();
  175. } catch (ClassNotFoundException e) {
  176. e.printStackTrace();
  177. }
  178. }
  179. @Override
  180. public Object getUploadInfo() {
  181. return obj;
  182. }
  183. };
  184. return logHandler;
  185. }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号