Spring事件监听器之@EventListener原理
Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
在spring中我们可以通过实现ApplicationListener接口或者@EventListener接口来实现事件驱动编程
比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
- public class OrderEvent extends ApplicationEvent {
- public OrderEvent(Object source) {
- super(source);
- }
- }
- @Component
- public class OrderEventListener {
- @EventListener
- public void listener(OrderEvent event) {
- System.out.println("i do OrderEventListener" );
- }
- }
- @Controller
- @RequestMapping("person")
- public class PersonController implements ApplicationContextAware {
- private ApplicationContext applicationContext;
- @Override
- public 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 Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( 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到容器中
1.2 EventListenerMethodProcessor和EventListenerFactory关系的建立
EventListenerMethodProcessor会在容器启动时被注入到容器中,他是一个BeanFactoryPostProcessor,EventListenerMethodProcessor和EventListenerFactory关系的建立就发生在其方法postProcessBeanFactory中
- public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
- @Nullable
- private List<EventListenerFactory> eventListenerFactories;
- //初始化eventListenerFactories
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
- this.beanFactory = beanFactory;
- //获取容器中所有的EventListenerFactory,并把他们实例化
- Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
-
- List<EventListenerFactory> 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)) {
- 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);
- }
- }
- //如果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");
- //获取容器中所有EventListenerFactory
- List<EventListenerFactory> 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 List<ResolvableType> declaredEventTypes;//存储方法的参数
- 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);
- @Override
- public 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;
- @Override
- public void dnsStart(Call call, String domainName) {
- super.dnsStart(call, domainName);
- dnsStartTime = System.nanoTime();
- }
- @Override
- public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
- super.dnsEnd(call, domainName, inetAddressList);
- dnsParseTime = System.nanoTime() - dnsStartTime;//dns解析耗时
- }
- //自动补全剩余实现方法
- }
EventListener.create方法在okHttpClient.newCall后执行
dnsParseTime可以算出dns解析耗时,还可以监听每次dns解析的domain,解析的结果inetAddressList。
这个是比较好用的。
问题是如何将这些数据回传回来呢
在OkHttpClient构造时传入自定义参数
- OkHttpClient.Builder builder = new OkHttpClient.Builder();
- final ResponseTag tag = new ResponseTag();
- tag.logHandler = logHandler;
- httpClient.newCall(requestBuilder.tag(tag).build()).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
-
- }
- @Override
- public 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);
- @Override
- public EventListener create(@NotNull Call call) {
- long callId = nextCallId.getAndIncrement();
- return new HttpEventListener(callId, (Client.ResponseTag) call.request().tag(), System.nanoTime());
- }
- };
- @Override
- public void callStart(Call call) {
- super.callStart(call);
- start_total_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public void dnsStart(Call call, String domainName) {
- super.dnsStart(call, domainName);
- start_dns_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
- super.dnsEnd(call, domainName, inetAddressList);
- dns_elapsed_time = System.currentTimeMillis() - start_dns_elapsed_time;//dns解析耗时
- logHandler.send("dns_elapsed_time", dns_elapsed_time);
- }
- @Override
- public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
- super.connectStart(call, inetSocketAddress, proxy);
- start_connect_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public void secureConnectStart(Call call) {
- super.secureConnectStart(call);
- start_tls_connect_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public 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);
- }
- @Override
- public 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);
- }
- @Override
- public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {
- super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
- }
- @Override
- public void connectionAcquired(Call call, Connection connection) {
- super.connectionAcquired(call, connection);
- }
- @Override
- public void connectionReleased(Call call, Connection connection) {
- super.connectionReleased(call, connection);
- }
- @Override
- public void requestHeadersStart(Call call) {
- super.requestHeadersStart(call);
- start_request_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public void requestHeadersEnd(Call call, Request request) {
- super.requestHeadersEnd(call, request);
- }
- @Override
- public void requestBodyStart(Call call) {
- super.requestBodyStart(call);
- }
- @Override
- public 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);
- }
- @Override
- public void responseHeadersStart(Call call) {
- super.responseHeadersStart(call);
- start_response_elapsed_time = System.currentTimeMillis();
- }
- @Override
- public void responseHeadersEnd(Call call, Response response) {
- super.responseHeadersEnd(call, response);
- }
- @Override
- public void responseBodyStart(Call call) {
- super.responseBodyStart(call);
- }
- @Override
- public 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);
- }
- @Override
- public void callEnd(Call call) {
- super.callEnd(call);
- total_elapsed_time = System.currentTimeMillis() - start_total_elapsed_time;
- logHandler.send("total_elapsed_time", total_elapsed_time);
- }
- @Override
- public 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() {
- @Override
- public 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();
- }
- }
- @Override
- public Object getUploadInfo() {
- return obj;
- }
- };
- return logHandler;
- }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。