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);
}
}
@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);
//t.event.internalEventListenerProcessor
//@EventListener注解处理器
if (!ainsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME))
;
}
//t.event.internalEventListenerProcessor
//内部管理的EventListenerFactory的bean名称
if (!ainsBeanDefinition(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;
}
如果容器中没有名字是t.event.internalEventListenerProcessor的bean,那么就注⼊⼀个EventListenerMethodProcessor到容器中
如果容器中没有名字是t.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 = BeansOfType(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 = BeanNamesForType(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, TargetBeanName(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 (!ains(targetType) &&!Name().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)) {
if (logger.isTraceEnabled()) {
}
}
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, Type(beanName));
//利⽤EventListenerFactory创建ApplicationListener,详情后⾯说
ApplicationListener<?> applicationListener =
//如果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.targetMethod = (!Proxy.isProxyClass(targetClass) ?MostSpecificMethod(method, targetClass) : hod);
//获取⽅法上的@EventListener注解对象
EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
}
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 {
}
}
}
}
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 = AndIncrement();
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解析耗时
}
/
/⾃动补全剩余实现⽅法
}
dnsParseTime可以算出dns解析耗时,还可以监听每次dns解析的domain,解析的结果inetAddressList。这个是⽐较好⽤的。
问题是如何将这些数据回传回来呢
在OkHttpClient构造时传⼊⾃定义参数
OkHttpClient.Builder builder = new OkHttpClient.Builder();
final ResponseTag tag = new ResponseTag();
tag.logHandler = logHandler;
@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.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 = AndIncrement();
return new HttpEventListener(callId, (Client.ResponseTag) quest().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);
spring启动流程面试回答}
@Override
public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy 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) {
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) {        tFailed(call, inetSocketAddress, proxy, protocol, ioe);
}
@Override
public void connectionAcquired(Call call, Connection connection) {
}
@Override
public void connectionReleased(Call call, Connection connection) {
}
@Override
public void requestHeadersStart(Call call) {
start_request_elapsed_time = System.currentTimeMillis();
}
@Override
public void requestHeadersEnd(Call call, Request request) {
}
@Override
public void requestBodyStart(Call call) {
}
@Override
public void requestBodyEnd(Call call, long byteCount) {
request_elapsed_time = System.currentTimeMillis() - start_request_elapsed_time;
logHandler.send("request_elapsed_time", request_elapsed_time);
}
@Override
public void responseHeadersStart(Call call) {
start_response_elapsed_time = System.currentTimeMillis();
}
@Override
public void responseHeadersEnd(Call call, Response response) {
}
@Override
public void responseBodyStart(Call call) {
}
@Override
public void responseBodyEnd(Call call, long 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 = Class().getMethod(setMethod + StringUtils.upperCase(key), Class.forName("java.lang.String"));                        setByKey.invoke(obj, value);
} else if (value instanceof Integer) {
Method setByKey = Class().getMethod(setMethod + StringUtils.upperCase(key), int.class);
setByKey.invoke(obj, value);
} else if (value instanceof Long) {
Method setByKey = Class().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;
}
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。