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中,在发送事件时候获取监听列表时用。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论