spring源码之事件监听机制(@eventlistener实现)
在看@eventlistener之前需要先知道 继承eventlistener方式在底层是怎么实现了,可以参见前一篇文章spring源码-事件监听机制(实现eventlistener接口)。
先梳理一下,首先ioc容器启动的时候,applicationcontext的refresh模板方法中,initapplicationeventmulticaster()方法中那个初始化了simpleapplicationeventmulticaster。
发送事件还是使用 applicationcontext.publishevent(或者applicationeventpublisher.publishevent),并且底层还是使用simpleapplicationeventmulticaster发送。
只是原来使用的是固定方法名称onapllicationevent进行调用,那拿到监听的类则可以使用父类调用子类的方法就可以了。
但是现在是自己写了一个随意定的名称那么怎么进行调用呢?其实自己去写框架的时候也可以思考一下,当然知道方法上有固定注解(@eventlistener)则还是可以找到该方法的。
还是先来一个demo,方便后续debug
一、@eventlistener方式的实现
定义事件类型,user对象就省略了
public class userevent extends applicationevent { /** * 实现父类方法 * @param source 数据源 */ public userevent(object source) { super(source); } }
两种发送事件的方式:
@service("eventuserservice") public class userservice implements applicationcontextaware, applicationeventpublisheraware { private applicationcontext applicationcontext; private applicationeventpublisher applicationeventpublisher; @override public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception { this.applicationcontext = applicationcontext; } @override public void setapplicationeventpublisher(applicationeventpublisher applicationeventpublisher) { this.applicationeventpublisher = applicationeventpublisher; } public string adduser(user user) { // 保存用户 user.setid(1l); user.setname("name-1"); // 发生事件(发邮件、发短信、、、) applicationcontext.publishevent(new userevent(user)); // 两种发生方式一致 applicationeventpublisher.publishevent(new userevent(user)); return "ok"; } }
@evnetlistener监听实现
@component public class userlistener { @eventlistener public void getuserevent(userevent userevent) { system.out.println("getuserevent-接受到事件:" + userevent); } @eventlistener public void getuserevent2(userevent userevent) { system.out.println("getuserevent2-接受到事件:" + userevent); } }
测试
@runwith(springjunit4classrunner.class) @springboottest(classes = kevintoolapplication.class ) public class annotationeventlistenertest { @autowired private userservice userservice; @test public void annotationeventtest() { userservice.adduser(new user()); } }
二、@eventlistener方式的源码分析
@eventlistener做什么了
@target({elementtype.method, elementtype.annotation_type}) @retention(retentionpolicy.runtime) @documented public @interface eventlistener { @aliasfor("classes") class<?>[] value() default {}; @aliasfor("value") class<?>[] classes() default {}; string condition() default ""; }
该注解可以定义在方法或者类上,可以定义监听的class,可以定义监听的条件(spring el表达式)。
那么问题来了,定义了class当然可以找到是谁发送事件过来,没有定义呢(可能是通过方法发入参,因为事件可以定义applicationevent或者object类型)。
如果idea导入了source和document(个人比较喜欢),则在注解中可以看见@see eventlistenermethodprocessor
,结构如下:
public class eventlistenermethodprocessor implements smartinitializingsingleton, applicationcontextaware, beanfactorypostprocessor { protected final log logger = logfactory.getlog(getclass()); @nullable private configurableapplicationcontext applicationcontext; @nullable private configurablelistablebeanfactory beanfactory; @nullable private list<eventlistenerfactory> eventlistenerfactories; private final eventexpressionevaluator evaluator = new eventexpressionevaluator(); private final set<class<?>> nonannotatedclasses = collections.newsetfrommap(new concurrenthashmap<>(64)); @override public void setapplicationcontext(applicationcontext applicationcontext) { assert.istrue(applicationcontext instanceof configurableapplicationcontext, "applicationcontext does not implement configurableapplicationcontext"); this.applicationcontext = (configurableapplicationcontext) applicationcontext; } @override public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) { this.beanfactory = beanfactory; map<string, eventlistenerfactory> beans = beanfactory.getbeansoftype(eventlistenerfactory.class, false, false); list<eventlistenerfactory> factories = new arraylist<>(beans.values()); annotationawareordercomparator.sort(factories); this.eventlistenerfactories = factories; } @override public void aftersingletonsinstantiated() { configurablelistablebeanfactory beanfactory = this.beanfactory; assert.state(this.beanfactory != null, "no configurablelistablebeanfactory set"); 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) { // an unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isdebugenabled()) { logger.debug("could not resolve target class for bean with name '" + beanname + "'", 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 { processbean(beanname, type); } catch (throwable ex) { throw new beaninitializationexception("failed to process @eventlistener " + "annotation on bean with name '" + beanname + "'", ex); } } } } } private void processbean(final string beanname, final class<?> targettype) { if (!this.nonannotatedclasses.contains(targettype) && annotationutils.iscandidateclass(targettype, eventlistener.class) && !isspringcontainerclass(targettype)) { map<method, eventlistener> annotatedmethods = null; try { 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); } } if (collectionutils.isempty(annotatedmethods)) { this.nonannotatedclasses.add(targettype); if (logger.istraceenabled()) { logger.trace("no @eventlistener annotations found on bean class: " + targettype.getname()); } } else { // non-empty set of methods configurableapplicationcontext context = this.applicationcontext; assert.state(context != null, "no applicationcontext set"); 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)) { method methodtouse = aoputils.selectinvocablemethod(method, context.gettype(beanname)); applicationlistener<?> applicationlistener = factory.createapplicationlistener(beanname, targettype, methodtouse); if (applicationlistener instanceof applicationlistenermethodadapter) { ((applicationlistenermethodadapter) applicationlistener).init(context, this.evaluator); } context.addapplicationlistener(applicationlistener); break; } } } if (logger.isdebugenabled()) { logger.debug(annotatedmethods.size() + " @eventlistener methods processed on bean '" + beanname + "': " + annotatedmethods); } } } } /** * determine whether the given class is an {@code org.springframework} * bean class that is not annotated as a user or test {@link component}... * which indicates that there is no {@link eventlistener} to be found there. * @since 5.1 */ private static boolean isspringcontainerclass(class<?> clazz) { return (clazz.getname().startswith("org.springframework.") && !annotatedelementutils.isannotated(classutils.getuserclass(clazz), component.class)); } }
实现了三个接口:
1)、实现了 applicationcontextaware
接口将其注入进来
2)、实现了beanfactorypostprocessor
接口,实现方法如下(只是没想通有applicationcontext则beanfactory的功能都有 了,为什么对实现一个接口,可能是执行时机也可能是觉得工厂干工厂的事好理解):
@override public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) { this.beanfactory = beanfactory; map<string, eventlistenerfactory> beans = beanfactory.getbeansoftype(eventlistenerfactory.class, false, false); list<eventlistenerfactory> factories = new arraylist<>(beans.values()); annotationawareordercomparator.sort(factories); this.eventlistenerfactories = factories; }
获取容器中所有eventbeanfactory或子类的bean,进行排序后存放到eventlistenerfactories,这里拿到了defaulteventlistenerfactory
这个非常的关键,在哪里注入的后续梳理。当然如果我们还添加了注解@transactionaleventlistener肯定还会有transactionaleventlistenerfactory
3)、实现了smartinitializingsingleton
接口,则在所以非抽象、非懒加载的单利都getbean完成后,才会调用aftersingletonsinstantiated
方法,这也算是smartinitializingsingleton
的使用场景分析(容器级别的处理)。
主要逻辑也在这里。
@override public void aftersingletonsinstantiated() { configurablelistablebeanfactory beanfactory = this.beanfactory; assert.state(this.beanfactory != null, "no configurablelistablebeanfactory set"); 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) { // an unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isdebugenabled()) { logger.debug("could not resolve target class for bean with name '" + beanname + "'", 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 { processbean(beanname, type); } catch (throwable ex) { throw new beaninitializationexception("failed to process @eventlistener " + "annotation on bean with name '" + beanname + "'", ex); } } } } }
string[] beannames = beanfactory.getbeannamesfortype(object.class);
很暴力的获取容器中所以的bean,并且进行遍历(总会找到我想要的)
autoproxyutils.determinetargetclass
根据bean的名称获取bean的class<?>,当然还考虑代理对象和继承等情况,最好获取当然的class,调processbean(beanname, type)方法。
private void processbean(final string beanname, final class<?> targettype) { if (!this.nonannotatedclasses.contains(targettype) && annotationutils.iscandidateclass(targettype, eventlistener.class) && !isspringcontainerclass(targettype)) { map<method, eventlistener> annotatedmethods = null; try { 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); } } if (collectionutils.isempty(annotatedmethods)) { this.nonannotatedclasses.add(targettype); if (logger.istraceenabled()) { logger.trace("no @eventlistener annotations found on bean class: " + targettype.getname()); } } else { // non-empty set of methods configurableapplicationcontext context = this.applicationcontext; assert.state(context != null, "no applicationcontext set"); 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)) { method methodtouse = aoputils.selectinvocablemethod(method, context.gettype(beanname)); applicationlistener<?> applicationlistener = factory.createapplicationlistener(beanname, targettype, methodtouse); if (applicationlistener instanceof applicationlistenermethodadapter) { ((applicationlistenermethodadapter) applicationlistener).init(context, this.evaluator); } context.addapplicationlistener(applicationlistener); break; } } } if (logger.isdebugenabled()) { logger.debug(annotatedmethods.size() + " @eventlistener methods processed on bean '" + beanname + "': " + annotatedmethods); } } } }
1、进来先判断,在nonannotatedclasses中没出现过,后面会往里注入值。并且类上或者方法上有eventlistener注解。
2、获取注解的方法map,key就是我们写的两个方法,value就是eventlistener和上面的参数信息
annotatedmethods = methodintrospector.selectmethods(targettype, (methodintrospector.metadatalookup<eventlistener>) method -> annotatedelementutils.findmergedannotation(method, eventlistener.class));
3、有可能获取到没有标注注解的方法,则在这里加到上面判断的nonannotatedclasses中,提高效率,因为拿了所有的bean。 比如spring boot的启动类就被加进去了。
4、下面就比较清楚了,遍历标注eventlistener注解的方法,遍历工厂,最主要的是:
applicationlistener<?> applicationlistener = factory.createapplicationlistener(beanname, targettype, methodtouse);
有不同的工厂创建不同的适配器对象(这里有简单工厂模式和适配器模式不知道理解对不),调用到defaulteventlistenerfactory
的方法,这个地方非常关键:
@override public applicationlistener<?> createapplicationlistener(string beanname, class<?> type, method method) { return new applicationlistenermethodadapter(beanname, type, method); }
这里返回了一个applicationlistenermethodadapter
对象(基础自eventlistener),内部的method属性就是我自己写的添加了@eventlistener的方法。并且将该listener放入spring容器中。
调用的是abstractapplicationcontext的方法,如下:
@override public void addapplicationlistener(applicationlistener<?> listener) { assert.notnull(listener, "applicationlistener must not be null"); if (this.applicationeventmulticaster != null) { this.applicationeventmulticaster.addapplicationlistener(listener); } this.applicationlisteners.add(listener); }
这样就将使用@eventlistener注解的方法使用包装的方式放入了simpleapplicationeventmulticaster
的 defaultretriever.applicationlisteners中,在后续发送事件时 获取监听器列表就能获取到了。
总结(与上面相同和不同之处)
相同:
- 1、applicationcontext的refresh方法还是初始化了simpleapplicationeventmulticaster
- 2、发送事件式还是先获取resolvabletype类型,再获取发送监听列表
不同:
- 1、获取监听列表返回的已经是处理过的列表。
- 2、添加了@eventlistener注解的自定义名称的方法,会在eventlistenermethodprocessor中的aftersingletonsinstantiated()方法中遍历所有 applicationcontext容器的单利bean。将所有添加了@eventlistener的方法注入到applicationcontext的applicationlisteners和初始化的simpleapplicationeventmulticaster的defaultretriever.applicationlisteners中,在发送事件时候获取监听列表时用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论