Spring事件发布监听,顺序监听,异步监听方式
最近在做公司的业务需要用到事件通知,比如启动成功打印日志,通知其他业务做相应的操作,就用到了spring的事件通知机制。
1. spring的事件通知
spring的事件通知本质上就是发布-订阅,即生产者-消费者;体现了观察者设计模式或者回调通知,那么spring的事件是如何使用的?
有3要素:发布者-->事件-->监听者
2. spring事件通知使用
spring的事件必须依赖spring容器,所以我在写demo的时候,需要spring-boot-starter。
<dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter</artifactid> <version>2.1.1.release</version> </dependency> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <version>1.18.4</version> </dependency> </dependencies>
2.1 spring的事件
spring的事件定义在applicationevent类中,我们可以根据自己的需要自定义事件实体javabean。
@data public class testspringevent extends applicationevent { /** * create a new applicationevent. * * @param source the object on which the event initially occurred (never {@code null}) */ public testspringevent(object source) { super(source); } private integer code; private string message; }
跟踪源码:
public abstract class applicationevent extends eventobject { /** use serialversionuid from spring 1.2 for interoperability. */ private static final long serialversionuid = 7099057708183571937l; /** system time when the event happened. */ private final long timestamp; /** * create a new applicationevent. * @param source the object on which the event initially occurred (never {@code null}) */ public applicationevent(object source) { super(source); this.timestamp = system.currenttimemillis(); } /** * return the system time in milliseconds when the event happened. */ public final long gettimestamp() { return this.timestamp; } }
可以看出applicationevent有属性时间戳,即事件的产生的时间,并有object source属性,这个source是有特定意义的,官方的doc是the object on which the event initially occurred.即发布事件的实体类。
进一步跟踪
public class eventobject implements java.io.serializable { private static final long serialversionuid = 5516075349620653480l; /** * the object on which the event initially occurred. */ protected transient object source; /** * constructs a prototypical event. * * @param source the object on which the event initially occurred. * @exception illegalargumentexception if source is null. */ public eventobject(object source) { if (source == null) throw new illegalargumentexception("null source"); this.source = source; } /** * the object on which the event initially occurred. * * @return the object on which the event initially occurred. */ public object getsource() { return source; } /** * returns a string representation of this eventobject. * * @return a a string representation of this eventobject. */ public string tostring() { return getclass().getname() + "[source=" + source + "]"; } }
定义了一个事件发生的不能序列化的对象
2.2 事件监听
2.2.1 接口方式实现
spring事件的监听由applicationlistener定义,我们写2个,来测试监听它执行的顺序
@component public class testapplicationlistener implements applicationlistener<testspringevent> { //@async public void onapplicationevent(testspringevent event) { system.out.println("code is:\t" + event.getcode() + ",\tmessage is:\t" + event.getmessage()); } } @component public class testapplicationlistenercopy implements applicationlistener<testspringevent> { //@async public void onapplicationevent(testspringevent event) { system.out.println("2:code is:\t" + event.getcode() + ",\tmessage is:\t" + event.getmessage()); } }
跟踪代码,可以看出applicationlistener是一个函数式接口
@functionalinterface public interface applicationlistener<e extends applicationevent> extends eventlistener { /** * handle an application event. * @param event the event to respond to */ void onapplicationevent(e event); }
spring事件监听器的默认是单线程同步执行,异步执行需要加上spring的@async注解,或者自定义线程池实现.
2.2.2 注解实现
也可以使用@eventlistener
package com.feng.spring.listener; import com.feng.spring.event.testspringevent; import org.springframework.context.event.eventlistener; import org.springframework.scheduling.annotation.async; import org.springframework.stereotype.component; @component public class testapplicationlistener2{ //@async @eventlistener public void onapplicationevent(testspringevent event) { system.out.println("step2:code is:\t" + event.getcode() + ",\tmessage is:\t" + event.getmessage()); } } @component public class testapplicationlistener2copy { //@async @eventlistener public void onapplicationevent(testspringevent event) { system.out.println("step3:code is:\t" + event.getcode() + ",\tmessage is:\t" + event.getmessage()); } }
同理写2个实现
2.3 事件发布
spring的事件的发布定义在applicationeventpublisher类中,而applicationcontext继承了这个类,因此applicationcontext具有发布事件的能力,而且已经注入spring的bean容器中,可直接获取。
public class springeventmain { public static void main(string[] args) { annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(); context.scan(springeventmain.class.getcanonicalname()); context.refresh(); testspringevent testspringevent = new testspringevent(new springeventmain()); testspringevent.setcode(10000); testspringevent.setmessage("---------my spring task event------------"); context.publishevent(testspringevent); } }
注意:
new testspringevent(new springeventmain())
这里的source是传入发布事件的实例对象。
运行后打印如下日志:
/software/jdk1.8.0_191/bin/java -javaagent:/software/ideaide/lib/idea_rt.jar=36631:/software/ideaide/bin -dfile.encoding=utf-8 -classpath /software/jdk1.8.0_191/jre/lib/charsets.jar:/software/jdk1.8.0_191/jre/lib/deploy.jar:/software/jdk1.8.0_191/jre/lib/ext/cldrdata.jar:/software/jdk1.8.0_191/jre/lib/ext/dnsns.jar:/software/jdk1.8.0_191/jre/lib/ext/jaccess.jar:/software/jdk1.8.0_191/jre/lib/ext/jfxrt.jar:/software/jdk1.8.0_191/jre/lib/ext/localedata.jar:/software/jdk1.8.0_191/jre/lib/ext/nashorn.jar:/software/jdk1.8.0_191/jre/lib/ext/sunec.jar:/software/jdk1.8.0_191/jre/lib/ext/sunjce_provider.jar:/software/jdk1.8.0_191/jre/lib/ext/sunpkcs11.jar:/software/jdk1.8.0_191/jre/lib/ext/zipfs.jar:/software/jdk1.8.0_191/jre/lib/javaws.jar:/software/jdk1.8.0_191/jre/lib/jce.jar:/software/jdk1.8.0_191/jre/lib/jfr.jar:/software/jdk1.8.0_191/jre/lib/jfxswt.jar:/software/jdk1.8.0_191/jre/lib/jsse.jar:/software/jdk1.8.0_191/jre/lib/management-agent.jar:/software/jdk1.8.0_191/jre/lib/plugin.jar:/software/jdk1.8.0_191/jre/lib/resources.jar:/software/jdk1.8.0_191/jre/lib/rt.jar:/home/huahua/ideaprojects/feng/spring-event/target/classes:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.1.release/spring-boot-starter-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot/2.1.1.release/spring-boot-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/spring-context/5.1.3.release/spring-context-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-aop/5.1.3.release/spring-aop-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-beans/5.1.3.release/spring-beans-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-expression/5.1.3.release/spring-expression-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.1.release/spring-boot-autoconfigure-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.1.release/spring-boot-starter-logging-2.1.1.release.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/home/huahua/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.1/log4j-to-slf4j-2.11.1.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:/home/huahua/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/home/huahua/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/home/huahua/.m2/repository/org/springframework/spring-core/5.1.3.release/spring-core-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-jcl/5.1.3.release/spring-jcl-5.1.3.release.jar:/home/huahua/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/home/huahua/.m2/repository/org/projectlombok/lombok/1.18.4/lombok-1.18.4.jar com.feng.spring.springeventmain
17:54:05.347 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/testapplicationlistener.class]
17:54:05.352 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/testapplicationlistener2.class]
17:54:05.353 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/testapplicationlistener3.class]
17:54:05.353 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/testapplicationlistenercopy.class]
17:54:05.358 [main] debug org.springframework.context.annotation.annotationconfigapplicationcontext - refreshing org.springframework.context.annotation.annotationconfigapplicationcontext@64b8f8f4
17:54:05.380 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalconfigurationannotationprocessor'
17:54:05.438 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerprocessor'
17:54:05.440 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerfactory'
17:54:05.443 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalautowiredannotationprocessor'
17:54:05.444 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalcommonannotationprocessor'
17:54:05.451 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'testapplicationlistener'
17:54:05.466 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'testapplicationlistener2'
17:54:05.470 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'testapplicationlistener3'
17:54:05.471 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'testapplicationlistenercopy'
17:54:05.490 [main] debug org.springframework.context.event.eventlistenermethodprocessor - 1 @eventlistener methods processed on bean 'testapplicationlistener2': {public void com.feng.spring.listener.testapplicationlistener2.onapplicationevent(com.feng.spring.event.testspringevent)=@org.springframework.context.event.eventlistener(condition=, value=[], classes=[])}
17:54:05.491 [main] debug org.springframework.context.event.eventlistenermethodprocessor - 1 @eventlistener methods processed on bean 'testapplicationlistener3': {public void com.feng.spring.listener.testapplicationlistener3.onapplicationevent(com.feng.spring.event.testspringevent)=@org.springframework.context.event.eventlistener(condition=, value=[], classes=[])}
step2:code is: 10000, message is: ---------my spring task event------------
step3:code is: 10000, message is: ---------my spring task event------------
code is: 10000, message is: ---------my spring task event------------
2:code is: 10000, message is: ---------my spring task event------------
process finished with exit code 0
说明spring事件发布订阅成功。同时使用注解的监听比实现类监听先监听,如果我们需要监听的执行顺序怎么办?比如某些监听器先执行?
2.4 spring顺序监听器
上面的示例,其实都是注解或者都是实现类,监听器是没有顺序的。如果我们要实现顺序监听呢?我么需要ordered接口的实现,spring提供的实现或者暴露的实现接口如下
如果需要执行顺序,spring提供smartapplicationlistener与genericapplicationlistener可供选择。
其中genericapplicationlistener,spring官方推荐我们提供adapter实现
/** * extended variant of the standard {@link applicationlistener} interface, * exposing further metadata such as the supported event and source type. * * <p>as of spring framework 4.2, this interface supersedes the class-based * {@link smartapplicationlistener} with full handling of generic event types. * * @author stephane nicoll * @since 4.2 * @see smartapplicationlistener * @see genericapplicationlisteneradapter */
/** * extended variant of the standard {@link applicationlistener} interface, * exposing further metadata such as the supported event and source type. * * <p>as of spring framework 4.2, this interface supersedes the class-based * {@link smartapplicationlistener} with full handling of generic event types. * * @author stephane nicoll * @since 4.2 * @see smartapplicationlistener * @see genericapplicationlisteneradapter */ public interface genericapplicationlistener extends applicationlistener<applicationevent>, ordered { /** * determine whether this listener actually supports the given event type. * @param eventtype the event type (never {@code null}) */ boolean supportseventtype(resolvabletype eventtype); /** * determine whether this listener actually supports the given source type. * <p>the default implementation always returns {@code true}. * @param sourcetype the source type, or {@code null} if no source */ default boolean supportssourcetype(@nullable class<?> sourcetype) { return true; } /** * determine this listener's order in a set of listeners for the same event. * <p>the default implementation returns {@link #lowest_precedence}. */ @override default int getorder() { return lowest_precedence; } }
其实applicationlistener在spring中提供了很多默认实现,其中就有smartapplicationlistener,智能监听器。
下面来试试
*/ public interface smartapplicationlistener extends applicationlistener<applicationevent>, ordered { /** * determine whether this listener actually supports the given event type. * @param eventtype the event type (never {@code null}) */ //supportseventtype与supportssourcetype同时true,监听器才会执行 //监听器支持的事件类型 boolean supportseventtype(class<? extends applicationevent> eventtype); /** * determine whether this listener actually supports the given source type. * <p>the default implementation always returns {@code true}. * @param sourcetype the source type, or {@code null} if no source */ //supportseventtype与supportssourcetype同时true,监听器才会执行 //监听事件发布的类 default boolean supportssourcetype(@nullable class<?> sourcetype) { return true; } /** * determine this listener's order in a set of listeners for the same event. * <p>the default implementation returns {@link #lowest_precedence}. */ @override default int getorder() { return lowest_precedence; } }
3个实现方法。支持的类型,支持的事件类,执行顺序
package com.feng.spring.listener; import com.feng.spring.springeventmain; import com.feng.spring.event.testspringevent; import org.springframework.context.applicationevent; import org.springframework.context.event.smartapplicationlistener; import org.springframework.stereotype.component; @component public class orderedlistener implements smartapplicationlistener { public boolean supportseventtype(class<? extends applicationevent> eventtype) { return eventtype== testspringevent.class; } public boolean supportssourcetype(class<?> sourcetype) { return springeventmain.class==sourcetype; } public int getorder() { return 5; } public void onapplicationevent(applicationevent event) { system.out.println("my execute step is 555555555555555555555555555"); } } @component public class orderedlistenercopy implements smartapplicationlistener { public boolean supportseventtype(class<? extends applicationevent> eventtype) { return eventtype== testspringevent.class; } public boolean supportssourcetype(class<?> sourcetype) { return springeventmain.class==sourcetype; } public int getorder() { return 6; } public void onapplicationevent(applicationevent event) { system.out.println("my execute step is 6666666666666666666666666666"); } }
同理写2个,执行结果如下:
/software/jdk1.8.0_191/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:46603,suspend=y,server=n -javaagent:/software/ideaide/lib/rt/debugger-agent.jar -dfile.encoding=utf-8 -classpath /software/jdk1.8.0_191/jre/lib/charsets.jar:/software/jdk1.8.0_191/jre/lib/deploy.jar:/software/jdk1.8.0_191/jre/lib/ext/cldrdata.jar:/software/jdk1.8.0_191/jre/lib/ext/dnsns.jar:/software/jdk1.8.0_191/jre/lib/ext/jaccess.jar:/software/jdk1.8.0_191/jre/lib/ext/jfxrt.jar:/software/jdk1.8.0_191/jre/lib/ext/localedata.jar:/software/jdk1.8.0_191/jre/lib/ext/nashorn.jar:/software/jdk1.8.0_191/jre/lib/ext/sunec.jar:/software/jdk1.8.0_191/jre/lib/ext/sunjce_provider.jar:/software/jdk1.8.0_191/jre/lib/ext/sunpkcs11.jar:/software/jdk1.8.0_191/jre/lib/ext/zipfs.jar:/software/jdk1.8.0_191/jre/lib/javaws.jar:/software/jdk1.8.0_191/jre/lib/jce.jar:/software/jdk1.8.0_191/jre/lib/jfr.jar:/software/jdk1.8.0_191/jre/lib/jfxswt.jar:/software/jdk1.8.0_191/jre/lib/jsse.jar:/software/jdk1.8.0_191/jre/lib/management-agent.jar:/software/jdk1.8.0_191/jre/lib/plugin.jar:/software/jdk1.8.0_191/jre/lib/resources.jar:/software/jdk1.8.0_191/jre/lib/rt.jar:/home/huahua/ideaprojects/feng/spring-event/target/classes:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.1.release/spring-boot-starter-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot/2.1.1.release/spring-boot-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/spring-context/5.1.3.release/spring-context-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-aop/5.1.3.release/spring-aop-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-beans/5.1.3.release/spring-beans-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-expression/5.1.3.release/spring-expression-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.1.release/spring-boot-autoconfigure-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.1.release/spring-boot-starter-logging-2.1.1.release.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/home/huahua/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.1/log4j-to-slf4j-2.11.1.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:/home/huahua/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/home/huahua/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/home/huahua/.m2/repository/org/springframework/spring-core/5.1.3.release/spring-core-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-jcl/5.1.3.release/spring-jcl-5.1.3.release.jar:/home/huahua/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/home/huahua/.m2/repository/org/projectlombok/lombok/1.18.4/lombok-1.18.4.jar:/software/ideaide/lib/idea_rt.jar com.feng.spring.springeventmain
connected to the target vm, address: '127.0.0.1:46603', transport: 'socket'
18:37:51.002 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/orderedlistener.class]
18:37:51.009 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/orderedlistenercopy.class]
18:37:51.017 [main] debug org.springframework.context.annotation.annotationconfigapplicationcontext - refreshing org.springframework.context.annotation.annotationconfigapplicationcontext@37d31475
18:37:51.055 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalconfigurationannotationprocessor'
18:37:51.129 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerprocessor'
18:37:51.132 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerfactory'
18:37:51.135 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalautowiredannotationprocessor'
18:37:51.136 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalcommonannotationprocessor'
18:37:51.145 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'orderedlistener'
18:37:51.154 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'orderedlistenercopy'
my execute step is 555555555555555555555555555
my execute step is 6666666666666666666666666666
disconnected from the target vm, address: '127.0.0.1:46603', transport: 'socket'
process finished with exit code 0
实现了顺序的监听。
2.5 异步监听
spring使用threadpooltaskexecutor来执行异步任务,其实就是schedulingtaskexecutor,使用@enableasync注解@async注解实现异步监听事件的调用
我们来试试
package com.feng.spring.config; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.scheduling.concurrent.threadpooltaskexecutor; import java.util.concurrent.executor; import java.util.concurrent.threadfactory; import java.util.concurrent.atomic.atomicinteger; @configuration public class asyncconfig { @bean public executor initexecutor(){ threadpooltaskexecutor executor = new threadpooltaskexecutor(); //定制线程名称,还可以定制线程group executor.setthreadfactory(new threadfactory() { private final atomicinteger threadnumber = new atomicinteger(1); @override public thread newthread(runnable r) { thread t = new thread(thread.currentthread().getthreadgroup(), r, "async-eventlistener-" + threadnumber.getandincrement(), 0); return t; } }); executor.setcorepoolsize(10); executor.setmaxpoolsize(20); executor.setkeepaliveseconds(5); executor.setqueuecapacity(100); // executor.setrejectedexecutionhandler(null); return executor; } }
@enableasync @component public class testapplicationlistener implements applicationlistener<testspringevent> { @async public void onapplicationevent(testspringevent event) { system.out.println("code is:\t" + event.getcode() + ",\tmessage is:\t" + event.getmessage()); //通过线程group/名称区别 system.out.println(thread.currentthread().getthreadgroup()+ "/" +thread.currentthread().getname()); } }
执行结果:
/software/jdk1.8.0_191/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:44287,suspend=y,server=n -javaagent:/software/ideaide/lib/rt/debugger-agent.jar -dfile.encoding=utf-8 -classpath /software/jdk1.8.0_191/jre/lib/charsets.jar:/software/jdk1.8.0_191/jre/lib/deploy.jar:/software/jdk1.8.0_191/jre/lib/ext/cldrdata.jar:/software/jdk1.8.0_191/jre/lib/ext/dnsns.jar:/software/jdk1.8.0_191/jre/lib/ext/jaccess.jar:/software/jdk1.8.0_191/jre/lib/ext/jfxrt.jar:/software/jdk1.8.0_191/jre/lib/ext/localedata.jar:/software/jdk1.8.0_191/jre/lib/ext/nashorn.jar:/software/jdk1.8.0_191/jre/lib/ext/sunec.jar:/software/jdk1.8.0_191/jre/lib/ext/sunjce_provider.jar:/software/jdk1.8.0_191/jre/lib/ext/sunpkcs11.jar:/software/jdk1.8.0_191/jre/lib/ext/zipfs.jar:/software/jdk1.8.0_191/jre/lib/javaws.jar:/software/jdk1.8.0_191/jre/lib/jce.jar:/software/jdk1.8.0_191/jre/lib/jfr.jar:/software/jdk1.8.0_191/jre/lib/jfxswt.jar:/software/jdk1.8.0_191/jre/lib/jsse.jar:/software/jdk1.8.0_191/jre/lib/management-agent.jar:/software/jdk1.8.0_191/jre/lib/plugin.jar:/software/jdk1.8.0_191/jre/lib/resources.jar:/software/jdk1.8.0_191/jre/lib/rt.jar:/home/huahua/ideaprojects/feng/spring-event/target/classes:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.1.release/spring-boot-starter-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot/2.1.1.release/spring-boot-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/spring-context/5.1.3.release/spring-context-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-aop/5.1.3.release/spring-aop-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-beans/5.1.3.release/spring-beans-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-expression/5.1.3.release/spring-expression-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.1.release/spring-boot-autoconfigure-2.1.1.release.jar:/home/huahua/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.1.release/spring-boot-starter-logging-2.1.1.release.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/home/huahua/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/home/huahua/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.1/log4j-to-slf4j-2.11.1.jar:/home/huahua/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:/home/huahua/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/home/huahua/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/home/huahua/.m2/repository/org/springframework/spring-core/5.1.3.release/spring-core-5.1.3.release.jar:/home/huahua/.m2/repository/org/springframework/spring-jcl/5.1.3.release/spring-jcl-5.1.3.release.jar:/home/huahua/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/home/huahua/.m2/repository/org/projectlombok/lombok/1.18.4/lombok-1.18.4.jar:/software/ideaide/lib/idea_rt.jar com.feng.spring.springeventmain
connected to the target vm, address: '127.0.0.1:44287', transport: 'socket'
19:08:24.692 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/config/asyncconfig.class]
19:08:24.730 [main] debug org.springframework.context.annotation.classpathbeandefinitionscanner - identified candidate component class: file [/home/huahua/ideaprojects/feng/spring-event/target/classes/com/feng/spring/listener/testapplicationlistener.class]
19:08:24.741 [main] debug org.springframework.context.annotation.annotationconfigapplicationcontext - refreshing org.springframework.context.annotation.annotationconfigapplicationcontext@37d31475
19:08:24.782 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalconfigurationannotationprocessor'
19:08:25.091 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerprocessor'
19:08:25.094 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.event.internaleventlistenerfactory'
19:08:25.099 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalautowiredannotationprocessor'
19:08:25.100 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalcommonannotationprocessor'
19:08:25.106 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.context.annotation.internalasyncannotationprocessor'
19:08:25.109 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'org.springframework.scheduling.annotation.proxyasyncconfiguration'
19:08:25.252 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'asyncconfig'
19:08:25.261 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'testapplicationlistener'
19:08:25.299 [main] debug org.springframework.beans.factory.support.defaultlistablebeanfactory - creating shared instance of singleton bean 'initexecutor'
19:08:25.330 [main] info org.springframework.scheduling.concurrent.threadpooltaskexecutor - initializing executorservice 'initexecutor'
code is: 10000, message is: ---------my spring task event------------
java.lang.threadgroup[name=main,maxpri=10]/async-eventlistener-1
看线程名称,已经异步执行了
[name=main,maxpri=10]/async-eventlistener-1
3. 总结
spring的事件通知demo已经完成,如果需要详细的spring事件从发布到订阅的过程,需要跟踪spring的applicationcontext的publishevent的过程,其实spring的applicationcontext的启动的过程中也定义了很详细的事件,使用intellij idea分析,如下:
spring事件通知的本质:生产者-消费者,体现了设计模式的观察者模式。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。