Spring Boot事件監聽

Spring 主要通過 ApplicationEvent 類和ApplicationListener接口提供事件處理,通過繼承 ApplicationEvent 類可以實現自定義事件,實現ApplicationListener接口並註冊爲Bean來監聽事件,詳細信息可參考Spring官網文檔SpringBoot官方文檔

官方提示:

應用程序事件

1 實現應用程序事件監聽器

import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

public class ApplicationStartingListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        System.out.println("ApplicationStartingEvent:" + event);
    }
}

2 在容器啓動前註冊應用程序事件監聽器 

import com.example.springbootdemo.config.ApplicationStartingListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        // 方式一
//        SpringApplication application = new SpringApplication(SpringBootDemoApplication.class);
//        application.addListeners(new ApplicationStartingListener());
//        application.run(args);
        // 方式二
        new SpringApplicationBuilder(SpringBootDemoApplication.class)
                .listeners(new ApplicationStartingListener())
                .run(args);
    }
}

通常的Spring Framework事件、自定義事件及事件監聽器

一、自定義事件

要實現自定義事件只需要繼承ApplicationEvent 類便可。發佈事件需要通過 ApplicationEventPublisher 類,可以通過 @Autowired 自動注入或實現 ApplicationEventPublisherAware 接口並註冊爲Bean來獲取該事件發佈類。

1 自定義事件實現

import org.springframework.context.ApplicationEvent;

public class TestEvent extends ApplicationEvent {

    public TestEvent(Object source) {
        super(source);
    }
}

2 自動注入獲取事件發佈類 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class TestEventPublisher {

    private ApplicationEventPublisher publisher;

    @Autowired
    public void setPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendTestEvent() {
        publisher.publishEvent(new TestEvent(this));
    }

}

3 實現 ApplicationEventPublisherAware 接口獲取事件發佈類

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

@Component
public class TestEventPublisher implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendTestEvent() {
        publisher.publishEvent(new TestEvent(this));
    }

}

二、事件監聽器

方式一:通過ApplicationListener接口實現事件監聽,實現ApplicationListener接口並註冊爲Bean

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

方式二:通過 @EventListener 註解實現事件監聽,該註解的 condition 還支持 SpEL 表達式。 

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EventNotifier {

    @EventListener
    public void testEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

三、異步監聽器

異步監聽器的實現可以依靠 @Async 註解,需要在啓動類上添加 @EnableAsync 註解開啓異步支持。

使用異步事件時,請注意以下限制:

  • 如果異步事件偵聽器拋出Exception,則不會傳播到調用者。請參閱AsyncUncaughtExceptionHandler以獲取更多詳細信息。

  • 異步事件偵聽器方法無法通過返回值來發布後續事件。如果您需要發佈另一個事件作爲處理的結果,請插入一個 ApplicationEventPublisher 以手動發佈事件。

1 啓動類開啓異步支持

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

2 監聽器實現異步 

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Async
    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EventNotifier {

    @Async
    @EventListener
    public void testEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

四、監聽器執行順序

監聽器順序通過 @Order 指定,異步監聽器不支持指定順序。

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EventNotifier {

    @Order(3)
    @EventListener
    public void testEvent3(TestEvent event) {
        log.info("testEvent3:" + event);
    }

    @Order(1)
    @EventListener
    public void testEvent1(TestEvent event) {
        log.info("testEvent1:" + event);
    }

}
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Slf4j
@Order(2)
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("TestEventListener:" + event);
    }
}

執行結果:

2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.springbootdemo.config.EventNotifier  : testEvent1:com.example.springbootdemo.config.TestEvent[[email protected]]
2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.s.config.TestEventListener           : TestEventListener:com.example.springbootdemo.config.TestEvent[[email protected]]
2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.springbootdemo.config.EventNotifier  : testEvent3:com.example.springbootdemo.config.TestEvent[[email protected]]

五、通用事件

自定義通用事件類

import org.springframework.context.ApplicationEvent;

public class CommonEvent<T> extends ApplicationEvent {

    public CommonEvent(T source) {
        super(source);
    }
}

由於泛型的類型擦除,發佈事件後會觸發所有類型的該通用事件。所以要指定類型繼承該通用事件纔會精確觸發監聽(即 class TestServiceEvent extends CommonEvent<TestService> { …​ }),或者實現 ResolvableTypeProvider 接口。

import org.springframework.context.ApplicationEvent;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;

public class CommonEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

    public CommonEvent(T source) {
        super(source);
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章