Spring事件监听器之@EventListener原理分析
目录
- Spring事件监听器之@EventListener原理
- 一、解析@EventListener前的准备工作
- 二、开始解析@EventListener
- EventListener.Factory
- EventListener.Factory监听网络请求全过程
- 问题是如何将这些数据回传回来呢
Spring事件监听器之@EventListener原理 Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
在spring中我们可以通过实现ApplicationListener接口或者@EventListener接口来实现事件驱动编程
比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
public class OrderEvent extends ApplicationEvent {public OrderEvent(Object source) {super(source); }}@Componentpublic class OrderEventListener{@EventListenerpublic void listener(OrderEvent event) {System.out.println("i do OrderEventListener" ); }}@Controller@RequestMapping("person")public class PersonController implements ApplicationContextAware {private ApplicationContext applicationContext; @Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext; }@ResponseBody@GetMapping("publishOrderEvent")public String publishOrderEvent() {applicationContext.publishEvent(new OrderEvent("我发布了事件!!!")); System.out.println(" publishOrderEvent "); return "发送事件了!"; }}
EventListenerMethodProcessor是@EventListener的解析类,他是一个SmartInitializingSingleton和BeanFactoryPostProcessor
一、解析@EventListener前的准备工作
1.1 EventListenerFactory和EventListenerMethodProcessor的注入
EventListenerFactory是把@EventListener标注的方法变成ApplicationListener的关键,其是在容器最初期(refresh方法发生前)就放到容器中去
public static SetregisterAnnotationConfigProcessors( BeanDefinitionRegistry registry, Object source) {//获取对象DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); //org.springframework.context.event.internalEventListenerProcessor//@EventListener注解处理器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)); }//org.springframework.context.event.internalEventListenerProcessor//内部管理的EventListenerFactory的bean名称if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); }return beanDefs; }
- 如果容器中没有名字是org.springframework.context.event.internalEventListenerProcessor的bean,那么就注入一个EventListenerMethodProcessor到容器中
- 如果容器中没有名字是org.springframework.context.event.internalEventListenerProcessor的bean,那么就注入一个DefaultEventListenerFactory到容器中
EventListenerMethodProcessor会在容器启动时被注入到容器中,他是一个BeanFactoryPostProcessor,EventListenerMethodProcessor和EventListenerFactory关系的建立就发生在其方法postProcessBeanFactory中
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { @Nullable private ListeventListenerFactories; //初始化eventListenerFactories @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {this.beanFactory = beanFactory; //获取容器中所有的EventListenerFactory,并把他们实例化Map beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false); List factories = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(factories); //将EventListenerFactory储存到缓存eventListenerFactories中,便于后来使用this.eventListenerFactories = factories; }}
EventListenerFactory的实例化时机只比BeanFactoryPostProcessor完点,他比BeanPostProcessor实例化时机早
二、开始解析@EventListener
EventListenerMethodProcessor是一个SmartInitializingSingleton,所以他会在所以bean实例化后,执行其afterSingletonsInstantiated方法
注意:只有单例的SmartInitializingSingleton,才会执行其afterSingletonsInstantiated方法
2.1 基本流程
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {@Override public void afterSingletonsInstantiated() {ConfigurableListableBeanFactory beanFactory = this.beanFactory; Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); // 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~一个一个的检查String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) {// if (!ScopedProxyUtils.isScopedTarget(beanName)) {Class> type = null; try {// 防止是代理,吧真实的类型拿出来type = AutoProxyUtils.determineTargetClass(beanFactory, beanName); }catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("", ex); }}if (type != null) {// 对专门的作用域对象进行兼容~~~~(绝大部分都用不着)if (ScopedObject.class.isAssignableFrom(type)) {try {Class> targetClass = AutoProxyUtils.determineTargetClass(beanFactory, 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 {// 真正处理这个Bean里面的方法们。。。processBean(beanName, type); }catch (Throwable ex) {throw new BeanInitializationException("", ex); }}}} } private void processBean(final String beanName, final Class> targetType) {//类上有@Component注解if (!this.nonAnnotatedClasses.contains(targetType) &&!targetType.getName().startsWith("java") &&!isSpringContainerClass(targetType)) {MapannotatedMethods = null; try {//获取类中用@EventListener标注方法的信息annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup ) 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); }}//如果annotatedMethods为空,那代表类中没有用@EventListener标注的方法if (CollectionUtils.isEmpty(annotatedMethods)) {this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) {logger.trace("" + targetType.getName()); }}else {// 类中存在用@EventListener标注的方法ConfigurableApplicationContext context = this.applicationContext; Assert.state(context != null, "No ApplicationContext set"); //获取容器中所有EventListenerFactoryList factories = this.eventListenerFactories; Assert.state(factories != null, "EventListenerFactory List not initialized"); for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {if (factory.supportsMethod(method)) {// 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关)// 这里注意:若你是JDK的代理类,请不要在实现类里书写@EventListener注解的监听器,否则会报错的。(CGLIB代理的木关系) Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); //利用EventListenerFactory创建ApplicationListener,详情后面说ApplicationListener> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse); //如果ApplicationListener是ApplicationListenerMethodAdapter类,那么执行其init方法if (applicationListener instanceof ApplicationListenerMethodAdapter) {((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); }//放到容器中context.addApplicationListener(applicationListener); //@EventListener方法只能解析一次break; }}}if (logger.isDebugEnabled()) {logger.debug(); }}}}}
获取容器中所有的类,把用@Component标注的类上所有的@EventListener方法用EventListenerFactory解析成一个ApplicationListener
@EventListener方法只要有到一个可以解析他的EventListenerFactory,就不会让其他EventListenerFactory解析他了 所以如果容器中存在多个EventListenerFactory,我要注意他的顺序
2.2 EventListenerFactory解析@EventListener
文章图片
public interface EventListenerFactory {//是否支持当前方法 boolean supportsMethod(Method method); //生成一个ApplicationListener ApplicationListener> createApplicationListener(String beanName, Class> type, Method method); }
EventListenerFactory有2个字类DefaultEventListenerFactory和TransactionalEventListenerFactory,DefaultEventListenerFactory是处理@EventListener,而TransactionalEventListenerFactory是处理@TransactionalEventListener的,Spring默认就有DefaultEventListenerFactory,而TransactionalEventListenerFactory是没有的,所以我们想要支持@TransactionalEventListener,就要注册一个TransactionalEventListenerFactory,也就是要说要使用@EnableTransactionManagement注解
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered { private int order = LOWEST_PRECEDENCE; @Override public boolean supportsMethod(Method method) {return true; } @Override public ApplicationListener> createApplicationListener(String beanName, Class> type, Method method) {return new ApplicationListenerMethodAdapter(beanName, type, method); }}
ApplicationListenerMethodAdapter一个ApplicationListener,他是用来包装@EventListener标注的方法
public class ApplicationListenerMethodAdapter implements GenericApplicationListener { private final String beanName; //@EventListener方法所属bean的名字 private final Method method; //@EventListener标注的方法 private final Method targetMethod; //@EventListener标注的真实方法对象,防止其是代理方法//方法申明,如public void demo.Ball.applicationContextEvent(demo.OrderEvent) private final AnnotatedElementKey methodKey; private final ListdeclaredEventTypes; //存储方法的参数 private final String condition; //@EventListener的condition private final int order; private ApplicationContext applicationContext; private EventExpressionEvaluator evaluator; //@EventListener的EventExpressionEvaluator public ApplicationListenerMethodAdapter(String beanName, Class> targetClass, Method method) {this.beanName = beanName; this.method = BridgeMethodResolver.findBridgedMethod(method); this.targetMethod = (!Proxy.isProxyClass(targetClass) ?AopUtils.getMostSpecificMethod(method, targetClass) : this.method); this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass); //获取方法上的@EventListener注解对象EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class); this.declaredEventTypes = resolveDeclaredEventTypes(method, ann); this.condition = (ann != null ? ann.condition() : null); this.order = resolveOrder(this.targetMethod); }public void onApplicationEvent(ApplicationEvent event) {processEvent(event); } public void processEvent(ApplicationEvent event) {Object[] args = resolveArguments(event); //根据@EventListener的condition,判断是否要处理if (shouldHandle(event, args)) {//调用方法Object result = doInvoke(args); if (result != null) {//如果有监听器可以监听这个结果,那么可以触发那个监听器handleResult(result); }else {logger.trace("No result object given - no result to handle"); }} }}
EventListener.Factory
EventListener.Factory监听网络请求全过程
网上介绍的并不多,关于它的使用方式,可能会存在很多坑。
主要是为了监听网络请求过程。
首先OkHttpClient.Builder.eventListenerFactory需要的是一个实现了EventListener接口的工厂类。
简单的实现方式。
public class HttpEventListener extends EventListener {private final long callId; final AtomicLong nextCallId = new AtomicLong(1L); @Overridepublic EventListener create(Call call) {long callId = nextCallId.getAndIncrement(); return new HttpEventListener(callId, System.nanoTime()); }public HttpEventListener(long callId, long callStartNanos) {this.callId = callId; this.callStartNanos = callStartNanos; }private long dnsStartTime; private long dnsParseTime; @Overridepublic void dnsStart(Call call, String domainName) {super.dnsStart(call, domainName); dnsStartTime = System.nanoTime(); }@Overridepublic void dnsEnd(Call call, String domainName, ListinetAddressList) {super.dnsEnd(call, domainName, inetAddressList); dnsParseTime = System.nanoTime() - dnsStartTime; //dns解析耗时}//自动补全剩余实现方法}
EventListener.create方法在okHttpClient.newCall后执行
dnsParseTime可以算出dns解析耗时,还可以监听每次dns解析的domain,解析的结果inetAddressList。
【Spring事件监听器之@EventListener原理分析】这个是比较好用的。
问题是如何将这些数据回传回来呢
在OkHttpClient构造时传入自定义参数
OkHttpClient.Builder builder = new OkHttpClient.Builder(); final ResponseTag tag = new ResponseTag(); tag.logHandler = logHandler; httpClient.newCall(requestBuilder.tag(tag).build()).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {}}); //自动补全剩余实现方法public class HttpEventListener extends EventListener {/*** 每次请求的标识*/private long callId = 1L; /*** 每次请求的开始时间,单位纳秒*/private final long callStartNanos; private long total_elapsed_time; private long dns_elapsed_time; private long connect_elapsed_time; private long tls_connect_elapsed_time; private long request_elapsed_time; private long wait_elapsed_time; private long response_elapsed_time; private Client.ResponseTag responseTag; private LogHandler logHandler; private long start_dns_elapsed_time; private long start_total_elapsed_time; private long start_connect_elapsed_time; private long start_tls_connect_elapsed_time; private long start_request_elapsed_time; private long start_response_elapsed_time; public HttpEventListener(long callId, Client.ResponseTag responseTag, long callStartNanos) {this.callId = callId; this.callStartNanos = callStartNanos; this.responseTag = responseTag; this.logHandler = responseTag.logHandler; }public static final Factory FACTORY = new Factory() {final AtomicLong nextCallId = new AtomicLong(1L); @Overridepublic EventListener create(@NotNull Call call) {long callId = nextCallId.getAndIncrement(); return new HttpEventListener(callId, (Client.ResponseTag) call.request().tag(), System.nanoTime()); }}; @Overridepublic void callStart(Call call) {super.callStart(call); start_total_elapsed_time = System.currentTimeMillis(); }@Overridepublic void dnsStart(Call call, String domainName) {super.dnsStart(call, domainName); start_dns_elapsed_time = System.currentTimeMillis(); }@Overridepublic void dnsEnd(Call call, String domainName, ListinetAddressList) {super.dnsEnd(call, domainName, inetAddressList); dns_elapsed_time = System.currentTimeMillis() - start_dns_elapsed_time; //dns解析耗时logHandler.send("dns_elapsed_time", dns_elapsed_time); }@Overridepublic void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {super.connectStart(call, inetSocketAddress, proxy); start_connect_elapsed_time = System.currentTimeMillis(); }@Overridepublic void secureConnectStart(Call call) {super.secureConnectStart(call); start_tls_connect_elapsed_time = System.currentTimeMillis(); }@Overridepublic void secureConnectEnd(Call call, Handshake handshake) {super.secureConnectEnd(call, handshake); tls_connect_elapsed_time = System.currentTimeMillis() - start_tls_connect_elapsed_time; logHandler.send("tls_connect_elapsed_time", tls_connect_elapsed_time); }@Overridepublic void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) {super.connectEnd(call, inetSocketAddress, proxy, protocol); connect_elapsed_time = System.currentTimeMillis() - start_connect_elapsed_time; logHandler.send("connect_elapsed_time", connect_elapsed_time); }@Overridepublic void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe); }@Overridepublic void connectionAcquired(Call call, Connection connection) {super.connectionAcquired(call, connection); }@Overridepublic void connectionReleased(Call call, Connection connection) {super.connectionReleased(call, connection); }@Overridepublic void requestHeadersStart(Call call) {super.requestHeadersStart(call); start_request_elapsed_time = System.currentTimeMillis(); }@Overridepublic void requestHeadersEnd(Call call, Request request) {super.requestHeadersEnd(call, request); }@Overridepublic void requestBodyStart(Call call) {super.requestBodyStart(call); }@Overridepublic void requestBodyEnd(Call call, long byteCount) {super.requestBodyEnd(call, byteCount); request_elapsed_time = System.currentTimeMillis() - start_request_elapsed_time; logHandler.send("request_elapsed_time", request_elapsed_time); }@Overridepublic void responseHeadersStart(Call call) {super.responseHeadersStart(call); start_response_elapsed_time = System.currentTimeMillis(); }@Overridepublic void responseHeadersEnd(Call call, Response response) {super.responseHeadersEnd(call, response); }@Overridepublic void responseBodyStart(Call call) {super.responseBodyStart(call); }@Overridepublic void responseBodyEnd(Call call, long byteCount) {super.responseBodyEnd(call, byteCount); response_elapsed_time = System.currentTimeMillis() - start_response_elapsed_time; wait_elapsed_time = System.currentTimeMillis() - start_request_elapsed_time; logHandler.send("response_elapsed_time", response_elapsed_time); logHandler.send("wait_elapsed_time", wait_elapsed_time); }@Overridepublic void callEnd(Call call) {super.callEnd(call); total_elapsed_time = System.currentTimeMillis() - start_total_elapsed_time; logHandler.send("total_elapsed_time", total_elapsed_time); }@Overridepublic void callFailed(Call call, IOException ioe) {super.callFailed(call, ioe); }}//利用反射将logHandler打回来的数据存到对象public static LogHandler getUplogHandler(final Object obj) {final String setMethod = "set"; LogHandler logHandler = new LogHandler() {@Overridepublic void send(String key, Object value) {try {if (value instanceof String) {Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), Class.forName("java.lang.String")); setByKey.invoke(obj, value); } else if (value instanceof Integer) {Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), int.class); setByKey.invoke(obj, value); } else if (value instanceof Long) {Method setByKey = obj.getClass().getMethod(setMethod + StringUtils.upperCase(key), long.class); setByKey.invoke(obj, value); }} catch (NoSuchMethodException e) {e.printStackTrace(); } catch (IllegalAccessException e) {e.printStackTrace(); } catch (InvocationTargetException e) {e.printStackTrace(); } catch (ClassNotFoundException e) {e.printStackTrace(); }}@Overridepublic Object getUploadInfo() {return obj; }}; return logHandler; }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- 关于SpringBoot整合Canal数据同步的问题
- SpringBoot中Dozer的使用小结
- Springboot整合Dozer实现深度复制的方法
- 探究Spring原理
- BUG小王子|SpringMVC序列化问题
- Spring|七十四、Spring与DAO操作 query()
- Spring|七十三、Spring与DAO操作 update()
- springboot|SpringBoot系统笔记
- spring|springboot简单小项目练习之增删改查-exercisePro01
- Spring|SpringBoot2——SpringBoot入门、SpringBoot的自动配置、配置文件和开发小技巧