欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring事件发布监听,顺序监听,异步监听方式

程序员文章站 2022-03-06 13:29:21
目录1. spring的事件通知2. spring事件通知使用2.1 spring的事件2.2 事件监听2.2.1 接口方式实现2.2.2 注解实现2.3 事件发布2.4 spring顺序监听器2.5...

最近在做公司的业务需要用到事件通知,比如启动成功打印日志,通知其他业务做相应的操作,就用到了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事件发布监听,顺序监听,异步监听方式

如果需要执行顺序,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事件发布监听,顺序监听,异步监听方式

spring事件通知的本质:生产者-消费者,体现了设计模式的观察者模式。

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