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事件通知的本质:生产者-消费者,体现了设计模式的观察者模式。

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

以上是 Spring事件发布监听,顺序监听,异步监听方式 的全部内容, 来源链接: utcz.com/p/251888.html

回到顶部