Spring事件监听器之@EventListener原理分析

网友投稿 670 2022-11-11

Spring事件-之@EventListener原理分析

Spring事件-之@EventListener原理分析

目录Spring事件-之@EventListener原理一、解析@EventListener前的准备工作二、开始解析@EventListenerEventListener.FactoryEventListener.Factory监听网络请求全过程问题是如何将这些数据回传回来呢

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 registerAnnotationConfigProcessors( BeanDefinjQvhpFJTsiitionRegistry 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 eventListenerFactories;

//初始化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)) {

Map annotatedMethods = 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");

//获取容器中所有EventListenerFactory

List 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 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 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 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 cahttp://ll) {

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;

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:CCF 日期计算
下一篇:CCF 最优灌溉
相关文章

 发表评论

暂时没有评论,来抢沙发吧~