spring監聽功能的使用

以創建訂單爲例,需要增加短信通知和事物通知,每次寫一個service也可以,最好的方式可以使用spring的事件監聽。

 

spring監聽器的使用:定義事件實現applicationEvent 定義監聽器是實現smartApplicationListener<> 發佈事件:applicationContext.publishEvent(orderCreateEvent)
https://blog.csdn.net/weixin_39035120/article/details/86225377

 

以下僞代碼是一個保存訂單的功能,並會發送短信消息:

/**
* Author heling on 2019/1/9
*/
@Service
public class OrderServiceImpl implements OrderService {
 
    @Override
    public void saveOrder() {
        //1.創建訂單
        System.out.println("訂單創建成功");
        //2.發送短信
        System.out.println("恭喜您訂單創建成功!----by sms");
    }
}
現有新需求:需要加一個微信通知的功能,代碼如下:

/**
* Author heling on 2019/1/9
*/
@Service
public class OrderServiceImpl implements OrderService {
 
    @Override
    public void saveOrder() {
        //1.創建訂單
        System.out.println("訂單創建成功");
        //2.發送短信
        System.out.println("恭喜您訂單創建成功!----by sms");
        //新需求:微信通知
        // 3.發送微信
        System.out.println("恭喜您訂單創建成功!----by wechat");
    }
}
存在問題:每次創建訂單需要加新功能(如新的通知方式),則要修改原有的類,難以維護。

違背設計模式的原則

1.單一職責:訂單保存功能,雜糅了消息通知這些功能

2.開閉原則:對拓展開放,對修改關閉

 

優化方案:使用觀察者模式,使創建訂單和消息通知進行分離,低耦合。可以選擇消息隊列,spring事件機制等,本文選擇Spring事件機制。

 

改造開始:

1.創建事件

package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationEvent;
 
import java.util.List;
 
/**
* Author heling on 2019/1/9
* 訂單創建活動事件
*/
public class OrderCreateEvent extends ApplicationEvent {
 
    private String name;
 
    //消息參數
    private List<String> contentList;
 
    public OrderCreateEvent(Object source, String name, List<String> contentList) {
        super(source);
        this.name = name;
        this.contentList = contentList;
    }
 
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<String> getContentList() {
        return contentList;
    }
    public void setContentList(List<String> contentList) {
        this.contentList = contentList;
    }
}
2.監聽器

package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
 
/**
* Author heling on 2019/1/9
* 短信監聽器
* ApplicationListener是無序的
*/
@Component
public class SmsListener implements ApplicationListener<OrderCreateEvent> {
 
    @Override
    public void onApplicationEvent(OrderCreateEvent event) {
        //發送短信
        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by sms");
 
    }
}
package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
 
/**
* Author heling on 2019/1/9
* 微信監聽器
*/
@Component
public class WechatListener implements ApplicationListener<OrderCreateEvent> {
 
    @Override
    public void onApplicationEvent(OrderCreateEvent event) {
        //發送微信
        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by wechat");
 
    }
}
3.事件發佈

package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.util.ArrayList;
 
/**
* Author heling on 2019/1/9
*/
@Service
public class OrderServiceImpl implements OrderService {
 
    @Resource
    private ApplicationContext applicationContext;
 
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
 
    @Override
    public void saveOrder() {
        //1.創建訂單
        System.out.println("訂單創建成功");
        //2.發佈事件
        ArrayList<String> contentList = new ArrayList<>();
        contentList.add("heling");
        contentList.add("123456789");
        OrderCreateEvent orderCreateEvent = new OrderCreateEvent(this, "訂單創建", contentList);
        applicationContext.publishEvent(orderCreateEvent);//ApplicationContext是我們的事件容器上層,我們發佈事件,也可以通過此容器完成發佈
        //applicationEventPublisher.publishEvent(orderCreateEvent);//也可以
        System.out.println("finished!");
    }
}
打印結果:

訂單創建成功

heling,您的訂單:123456789創建成功! ----by sms

heling,您的訂單:123456789創建成功! ----by wechat

finished!

如何異步執行監聽器?

1.springboot開啓事件異步設置

package com.pengshu.magicwallet;
 
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
@SpringBootApplication
@MapperScan("com.pengshu.magicwallet.mapper")
@PropertySource("classpath:authority.properties")
@EnableTransactionManagement
@EnableAsync //開啓spring事件異步設置,加@Async註解
public class MagicWalletAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(MagicWalletAdminApplication.class, args);
    }
}
 

2.監聽器類或方法添加@Async註解

打印結果:

訂單創建成功

finished!

heling,您的訂單:123456789創建成功! ----by sms

heling,您的訂單:123456789創建成功! ----by wechat

如何制定監聽器執行順序?

package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
 
/**
* Author heling on 2019/1/9
* 微信監聽器
* SmartApplicationListener可以設置順序等
*/
@Component
public class WechatListener implements SmartApplicationListener {
 
    //設置監聽優先級
    @Override
    public int getOrder() {
        return 1;
    }
 
    //監聽器智能所在之一,能夠根據事件類型動態監聽
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == OrderCreateEvent.class;
    }
 
    //監聽器智能所在之二,能夠根據事件發佈者類型動態監聽
    @Override
    public boolean supportsSourceType(Class<?> aClass) {
        return aClass == OrderServiceImpl.class;
    }
 
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        OrderCreateEvent event = (OrderCreateEvent) applicationEvent;
        //發送微信
        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by wechat");
 
    }
 
//    @Override
//    @Async
//    public void onApplicationEvent(OrderCreateEvent event) {
//
//        //發送微信
//        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by wechat");
//
//    }
}
package com.pengshu.magicwallet.admin.test;
 
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
 
/**
* Author heling on 2019/1/9
* 短信監聽器
*/
@Component
public class SmsListener implements SmartApplicationListener {
 
    @Override
    public int getOrder() {
        return 2;
    }
 
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == OrderCreateEvent.class;
    }
 
    @Override
    public boolean supportsSourceType(Class<?> aClass) {
        return aClass == OrderServiceImpl.class;
    }
 
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        OrderCreateEvent event = (OrderCreateEvent) applicationEvent;
        //發送短信
        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by sms");
 
    }
 
//    @Override
//    @Async
//    public void onApplicationEvent(OrderCreateEvent event) {
//
//        //發送短信
//        System.out.println(event.getContentList().get(0) + ",您的訂單:" + event.getContentList().get(1) + "創建成功! ----by sms");
//
//    }
}
 

打印結果:

訂單創建成功

heling,您的訂單:123456789創建成功! ----by wechat

heling,您的訂單:123456789創建成功! ----by sms

finished!

 

在實現了SmartApplicationListener的監聽器中,我們通過重寫GetOrder方法來修改不同監聽器的順序,優先級越小,則越先被調用。通過配置不同的優先級,且讓監聽器之間阻塞調用。我們就能實現流水線式的有序事件調用,這在實際應用場景中還是蠻有意義的
————————————————
版權聲明:本文爲CSDN博主「超人不會飛2018」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_39035120/article/details/86225377

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