当前位置: 代码网 > it编程>编程语言>Java > Spring源码之事件监听机制详解(@EventListener实现方式)

Spring源码之事件监听机制详解(@EventListener实现方式)

2024年08月13日 Java 我要评论
spring源码之事件监听机制(@eventlistener实现)在看@eventlistener之前需要先知道 继承eventlistener方式在底层是怎么实现了,可以参见前一篇文章spring源

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中,在发送事件时候获取监听列表时用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com