spring事件驅動編程--demo

引用: https://juejin.im/post/5d93fa78f265da5b991d5133

談到Spring 事件驅動模型,我想大家都不陌生,事件驅動模型,通常也可以說是觀察者設計模式。
java本身也自帶了對事件驅動的支持,但是大部分都是用於我們的客戶端開發,比如GUI ,Swing這些,而Spring 則在java的基礎上,擴展了對事件驅動的支持。

廢話不多說,直接擼代碼。

事件驅動編程

自定義ApplicationEvent

我們新建一個類NotifyEvent 繼承ApplicationEvent,用於封裝我們事件額外的信息,這裏則是String類型的msg,用於記錄詳細的事件內容。

public class NotifyEvent extends ApplicationEvent {

    @Getter
    private String msg;
    
    public NotifyEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }
}

自定義事件發佈者Publisher

NotifyPublisher用於我們事件的發佈工作,該類實現了ApplicationContextAware並重寫了setApplicationContext 方法,這一步的目的是可以獲取我們Spring的應用上下文,因爲事件的發佈是需要應用上下文來做的.

@Component
@Slf4j
public class NotifyPublisher implements ApplicationContextAware {
    private ApplicationContext ctx; //應用上下文


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx= applicationContext;
    }

    public void publishEvent(int type, String json) {
        ctx.publishEvent(new NotifyEvent(type, json));
    }
}

自定義事件訂閱者Listener

最後一步就是實現一個類作爲事件的訂閱者啦,當事件發佈時,會通知訂閱者,然後訂閱者做相關的處理,比如新用戶註冊發送事件自動發送歡迎郵件等等。

@Component
@Slf4j
//指定具體的事件類型: E extends ApplicationEvent
public class NotifyListener implements ApplicationListener<NotifyEvent> {
     @Override
    public void onApplicationEvent(NotifyEvent event) {
        log.info("收到事件{}",event.getMsg());
    }
}

@EventListener
Spring 4.2 版本更新的EventListener,可以很方便幫助我們實現事件與方法的綁定,只需要在目標方法上加上EventListener即可。

@Component
public class MqListener {

    @EventListener
    //參數NotifyEvent ,當有NotifyEvent 類型的事件發生時,交給sayHello方法處理
    public void sayHello(NotifyEvent notifyEvent){
         log.info("收到事件{}",event.getMsg());
    }
}

測試

public class AuthenticationCenterApplication implements CommandLineRunner {
	
	//略...

    @Autowired
    private NotifyPublisher mqPublisher;

    @Override
    public void run(String... args) throws Exception {
        AtomicInteger loop = new AtomicInteger(1);
        while (loop.get() < 10) {
            mqPublisher.publishEvent(1, "nihao_" + loop.getAndIncrement());
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

後臺打印結果:
在這裏插入圖片描述
每隔一秒種打印一次數據。

但是可以看到上述的執行內容,全部是由main線程執行的。

異步事件驅動編程

Spring 也提供了@Async 註解來實現異步事件的消費。用起來也很簡單,只需要在

  • @EventListener上加上@Async
  • 或者onApplicationEvent方法上添加@Async

springboot開啓@EnableAsync 即可支持異步。

@EnableAsync
public class AuthenticationCenterApplication implements CommandLineRunner {
}

執行結果: 在這裏插入圖片描述

自定義線程池
Springboot默認的異步線程池名爲"taskExecutor":org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor, 可以通過注入java.util.concurrent.Executor`進行覆蓋:

   @Bean
    public Executor taskExecutor(){
        return new ThreadPoolExecutor(2,
                4,
                1000,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue(5),
                new UserThreadFactory("myAysnc")
        );
    }

    static class UserThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger nextId = new AtomicInteger(1);

        UserThreadFactory(String whatFeatureOfGroup) {
            namePrefix = whatFeatureOfGroup + "-pool-";
        }

        @Override
        public Thread newThread(Runnable task) {
            String name = namePrefix + nextId.getAndIncrement();
            Thread thread = new Thread(null, task, name,0);
            return thread;
        }

    }

打印結果:
在這裏插入圖片描述

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