溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何實現(xiàn)Spring事件發(fā)布監(jiān)聽、順序監(jiān)聽和異步監(jiān)聽

發(fā)布時間:2021-12-28 12:56:19 來源:億速云 閱讀:252 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)如何實現(xiàn)Spring事件發(fā)布監(jiān)聽、順序監(jiān)聽和異步監(jiān)聽的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

    1. Spring的事件通知

    Spring的事件通知本質(zhì)上就是發(fā)布-訂閱,即生產(chǎn)者-消費者;體現(xiàn)了觀察者設(shè)計模式或者回調(diào)通知,那么Spring的事件是如何使用的?

    有3要素:發(fā)布者-->事件-->監(jiān)聽者

    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類中,我們可以根據(jù)自己的需要自定義事件實體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有屬性時間戳,即事件的產(chǎn)生的時間,并有Object source屬性,這個source是有特定意義的,官方的doc是The object on which the Event initially occurred.即發(fā)布事件的實體類。

    進一步跟蹤

    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 + "]";
        }
    }

    定義了一個事件發(fā)生的不能序列化的對象

    2.2 事件監(jiān)聽

    2.2.1 接口方式實現(xiàn)

    Spring事件的監(jiān)聽由ApplicationListener定義,我們寫2個,來測試監(jiān)聽它執(zhí)行的順序

    @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是一個函數(shù)式接口

    @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事件監(jiān)聽器的默認(rèn)是單線程同步執(zhí)行,異步執(zhí)行需要加上Spring的@Async注解,或者自定義線程池實現(xiàn).

    2.2.2 注解實現(xiàn)

    也可以使用@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個實現(xiàn)

    2.3 事件發(fā)布

    Spring的事件的發(fā)布定義在ApplicationEventPublisher類中,而ApplicationContext繼承了這個類,因此ApplicationContext具有發(fā)布事件的能力,而且已經(jīng)注入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是傳入發(fā)布事件的實例對象。

    運行后打印如下日志:

    /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事件發(fā)布訂閱成功。同時使用注解的監(jiān)聽比實現(xiàn)類監(jiān)聽先監(jiān)聽,如果我們需要監(jiān)聽的執(zhí)行順序怎么辦?比如某些監(jiān)聽器先執(zhí)行?

    2.4 Spring順序監(jiān)聽器

    上面的示例,其實都是注解或者都是實現(xiàn)類,監(jiān)聽器是沒有順序的。如果我們要實現(xiàn)順序監(jiān)聽呢?我么需要Ordered接口的實現(xiàn),Spring提供的實現(xiàn)或者暴露的實現(xiàn)接口如下

    如何實現(xiàn)Spring事件發(fā)布監(jiān)聽、順序監(jiān)聽和異步監(jiān)聽

    如果需要執(zhí)行順序,Spring提供SmartApplicationListener與GenericApplicationListener可供選擇。

    其中GenericApplicationListener,Spring官方推薦我們提供adapter實現(xiàn)

    /**
     * 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中提供了很多默認(rèn)實現(xiàn),其中就有SmartApplicationListener,智能監(jiān)聽器。

    下面來試試

     */
    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,監(jiān)聽器才會執(zhí)行
          //監(jiān)聽器支持的事件類型
    	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,監(jiān)聽器才會執(zhí)行
          //監(jiān)聽事件發(fā)布的類
    	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個實現(xiàn)方法。支持的類型,支持的事件類,執(zhí)行順序

    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個,執(zhí)行結(jié)果如下:

    /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

    實現(xiàn)了順序的監(jiān)聽。

    2.5 異步監(jiān)聽

    Spring使用ThreadPoolTaskExecutor來執(zhí)行異步任務(wù),其實就是SchedulingTaskExecutor,使用@EnableAsync注解@Async注解實現(xiàn)異步監(jiān)聽事件的調(diào)用

    我們來試試

    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/名稱區(qū)別
            System.out.println(Thread.currentThread().getThreadGroup()+ "/" +Thread.currentThread().getName());
        }
    }

    執(zhí)行結(jié)果:

    /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

    看線程名稱,已經(jīng)異步執(zhí)行了

    [name=main,maxpri=10]/async-eventListener-1

    3. 總結(jié)

    Spring的事件通知demo已經(jīng)完成,如果需要詳細(xì)的Spring事件從發(fā)布到訂閱的過程,需要跟蹤Spring的ApplicationContext的publishEvent的過程,其實Spring的ApplicationContext的啟動的過程中也定義了很詳細(xì)的事件,使用intellij idea分析,如下:

    如何實現(xiàn)Spring事件發(fā)布監(jiān)聽、順序監(jiān)聽和異步監(jiān)聽

    Spring事件通知的本質(zhì):生產(chǎn)者-消費者,體現(xiàn)了設(shè)計模式的觀察者模式。

    感謝各位的閱讀!關(guān)于“如何實現(xiàn)Spring事件發(fā)布監(jiān)聽、順序監(jiān)聽和異步監(jiān)聽”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI