最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于spring如何實現(xiàn)事件驅(qū)動實例代碼

 更新時間:2019年04月08日 09:43:06   作者:稀飯下雪  
這篇文章主要給大家介紹了關(guān)于基于spring如何實現(xiàn)事件驅(qū)動的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

干貨點

通過閱讀該篇博客,你可以了解了解java的反射機制、可以了解如何基于spring生命周期使用自定義注解解決日常研發(fā)問題。具體源碼可以點擊鏈接

問題描述

在日常研發(fā)中,經(jīng)常會遇見業(yè)務(wù)A的某個action被觸發(fā)后,同時觸發(fā)業(yè)務(wù)B的action的行為,這種單對單的形式可以直接在業(yè)務(wù)A的action執(zhí)行結(jié)束后直接調(diào)用業(yè)務(wù)B的action,那么如果是單對多的情況呢?

方案解決

這里提供一種在日常研發(fā)中經(jīng)常使用到的機制,基于spring實現(xiàn)的事件驅(qū)動,即在業(yè)務(wù)A的action執(zhí)行完,拋出一個事件,而業(yè)務(wù)B、C、D等監(jiān)聽到該事件后處理相應(yīng)的業(yè)務(wù)。

場景范例

這里提供一個場景范例,該范例基于springboot空殼項目實現(xiàn),具體可以查看源碼,此處只梳理關(guān)鍵步驟。

步驟一:

定義一個注解,標(biāo)志接收事件的注解,即所有使用了該注解的函數(shù)都會在對應(yīng)事件被拋出的時候被調(diào)用,該注解實現(xiàn)比較簡單,代碼如下

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc 接收事件的注解
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ReceiveAnno {

 // 監(jiān)聽的事件
 Class clz();
}

如果想了解注解多個參數(shù)的意義是什么的可以點擊鏈接查看博主之前寫過文章。

定義事件接口

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc
 */
public interface IEvent {
}

所有事件都需要實現(xiàn)該接口,主要是為了后面泛型和類型識別。

定義MethodInfo

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc
 */
public class MethodInfo {

 public Object obj;
 public Method method;

 public static MethodInfo valueOf(Method method, Object obj) {

 MethodInfo info = new MethodInfo();
 info.method = method;
 info.obj = obj;
 return info;
 }

 public Object getObj() {
 return obj;
 }

 public Method getMethod() {
 return method;
 }
}

該類只是做了Object和Method的封裝,沒有其他作用。

步驟二:

實現(xiàn)一個事件容器,該容器的作用是存放各個事件以及需要觸發(fā)的各個業(yè)務(wù)的method的對應(yīng)關(guān)系。

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc 事件容器
 */
public class EventContainer {

 private static Map<Class<IEvent>, List<MethodInfo>> eventListMap = new HashMap<>();

 public static void addEventToMap(Class clz, Method method, Object obj) {

 List<MethodInfo> methodInfos = eventListMap.get(clz);
 if (methodInfos == null) {
 methodInfos = new ArrayList<>();
 eventListMap.put(clz, methodInfos);
 }

 methodInfos.add(MethodInfo.valueOf(method, obj));
 }

 public static void submit(Class clz) {

 List<MethodInfo> methodInfos = eventListMap.get(clz);
 if (methodInfos == null) {
 return;
 }

 for (MethodInfo methodInfo : methodInfos) {
 Method method = methodInfo.getMethod();
 try {
 method.setAccessible(true);
 method.invoke(methodInfo.getObj());
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } catch (InvocationTargetException e) {
 e.printStackTrace();
 }
 }
 }
}

其中的addEventToMap函數(shù)的作用是將對應(yīng)的事件、事件觸發(fā)后需要觸發(fā)的對應(yīng)業(yè)務(wù)內(nèi)的Method存放在eventListMap內(nèi);而submit函數(shù)會在其他業(yè)務(wù)類內(nèi)拋出事件的時候被調(diào)用,而作用是從eventListMap中取出對應(yīng)的Method,并通過反射觸發(fā)。

步驟三:

實現(xiàn)事件處理器,該事件處理器的作用是在bean被spring容器實例化后去判斷對應(yīng)的bean是否有相應(yīng)函數(shù)加了@ReceiveAnno注解,如果有則從中取出對應(yīng)的Event并放入EventContainer中。

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc 事件處理器
 */
@Component
public class EventProcessor extends InstantiationAwareBeanPostProcessorAdapter {

 @Override
 public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

 ReflectionUtils.doWithLocalMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
 @Override
 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {

 ReceiveAnno anno = method.getAnnotation(ReceiveAnno.class);
 if (anno == null) {
  return;
 }

 Class clz = anno.clz();
 try {
  if (!IEvent.class.isInstance(clz.newInstance())) {
  FormattingTuple message = MessageFormatter.format("{}沒有實現(xiàn)IEvent接口", clz);
  throw new RuntimeException(message.getMessage());
  }
 } catch (InstantiationException e) {
  e.printStackTrace();
 }

 EventContainer.addEventToMap(clz, method, bean);
 }
 });

 return super.postProcessAfterInstantiation(bean, beanName);
 }

}

關(guān)于InstantiationAwareBeanPostProcessorAdapter的描述,有需要的可以查看我之前的文章,其中比較詳細(xì)描述到Spring中的InstantiationAwareBeanPostProcessor類的作用。

步驟四:

對應(yīng)的業(yè)務(wù)類的實現(xiàn)如下:

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc
 */
@Slf4j
@Service
public class AFuncService implements IAFuncService {

 @Override
 public void login() {
 log.info("[{}]拋出登錄事件 ... ", this.getClass());
 EventContainer.submit(LoginEvent.class);
 }
}

A業(yè)務(wù)類,login會在被調(diào)用的生活拋出LoginEvent事件。

/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc
 */
@Service
@Slf4j
public class BFuncService implements IBFuncService {

 @ReceiveAnno(clz = LoginEvent.class)
 private void doAfterLogin() {
 log.info("[{}]監(jiān)聽到登錄事件 ... ", this.getClass());
 }
}
/**
 * @author xifanxiaxue
 * @date 3/31/19
 * @desc
 */
@Service
@Slf4j
public class CFuncService implements ICFuncService {

 @ReceiveAnno(clz = LoginEvent.class)
 private void doAfterLogin() {
 log.info("[{}]監(jiān)聽到登錄事件 ... ", this.getClass());
 }
}

B和C業(yè)務(wù)類的doAfterLogin都分別加了注解 @ReceiveAnno(clz = LoginEvent.class) ,在監(jiān)聽到事件LoginEvent后被觸發(fā)。
為了觸發(fā)方便,我在spring提供的測試類內(nèi)加了實現(xiàn),代碼如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventMechanismApplicationTests {

 @Autowired
 private AFuncService aFuncService;

 @Test
 public void contextLoads() {
 aFuncService.login();
 }
}

可以從中看出啟動該測試類后,會調(diào)用業(yè)務(wù)A的login函數(shù),而我們要的效果是B業(yè)務(wù)類和C業(yè)務(wù)類的doAfterLogin函數(shù)會被自動觸發(fā),那么結(jié)果如何呢?

結(jié)果打印

我們可以從結(jié)果打印中看到,在業(yè)務(wù)類A的login函數(shù)觸發(fā)后,業(yè)務(wù)類B和業(yè)務(wù)類C都監(jiān)聽到了監(jiān)聽到登錄事件,證明該機制正常解決了單對多的行為觸發(fā)問題。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 詳解Java單例模式中的餓漢和懶漢模式

    詳解Java單例模式中的餓漢和懶漢模式

    這篇文章主要介紹了詳解Java單例模式中的餓漢和懶漢模式,單例模式中有兩種模式一種是餓漢模式,一種是懶漢模式,那么他們有什么區(qū)別呢,需要的朋友可以參考下本文
    2023-04-04
  • 關(guān)于Java中ArrayList的源碼分析

    關(guān)于Java中ArrayList的源碼分析

    這篇文章主要從源碼角度帶大家深入了解一下Java中ArrayList的構(gòu)造方法和屬性等知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-05-05
  • springboot創(chuàng)建的web項目整合Quartz框架的項目實踐

    springboot創(chuàng)建的web項目整合Quartz框架的項目實踐

    本文主要介紹了springboot創(chuàng)建的web項目整合Quartz框架的項目實踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Java序列化和反序列化示例介紹

    Java序列化和反序列化示例介紹

    大家好,本篇文章主要講的是Java序列化和反序列化示例介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Maven install 報錯

    Maven install 報錯"程序包不存在"問題的解決方法

    這篇文章主要介紹了Maven install 報錯"程序包不存在"問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java雜談之如何優(yōu)化寫出漂亮高效的代碼

    Java雜談之如何優(yōu)化寫出漂亮高效的代碼

    不一致的代碼會造成認(rèn)知上的負(fù)擔(dān),在一個系統(tǒng)中,做類似的事情,卻有不同的做法,或者起到類似作用的事物,卻有不同的名字,讓人困惑
    2021-09-09
  • 云服務(wù)器環(huán)境搭建及部署(jdk、mysql、redis、nginx環(huán)境搭建)詳細(xì)步驟

    云服務(wù)器環(huán)境搭建及部署(jdk、mysql、redis、nginx環(huán)境搭建)詳細(xì)步驟

    這篇文章主要給大家介紹了關(guān)于云服務(wù)器環(huán)境搭建及部署(jdk、mysql、redis、nginx環(huán)境搭建)詳細(xì)步驟的相關(guān)資料,要在云服務(wù)器上搭建JDK、MySQL、Redis和Nginx的環(huán)境,可以按照以下步驟進行操作,需要的朋友可以參考下
    2024-01-01
  • Spring的@Autowired加到接口上但獲取的是實現(xiàn)類的問題

    Spring的@Autowired加到接口上但獲取的是實現(xiàn)類的問題

    這篇文章主要介紹了Spring的@Autowired加到接口上但獲取的是實現(xiàn)類的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Java中自定義類的實現(xiàn)詳解

    Java中自定義類的實現(xiàn)詳解

    自定義類是Java中最基本、也是最重要的組成部分之一,使用者可以根據(jù)需求創(chuàng)建自己的數(shù)據(jù)類型,從而更加高效地構(gòu)建程序,本文就來為大家詳細(xì)講講Java中自定義類的實現(xiàn)與使用吧
    2023-05-05
  • Spring Boot2配置服務(wù)器訪問日志過程解析

    Spring Boot2配置服務(wù)器訪問日志過程解析

    這篇文章主要介紹了Spring Boot2配置服務(wù)器訪問日志過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11

最新評論

若尔盖县| 抚宁县| 临清市| 咸阳市| 三台县| 滕州市| 扶绥县| 潼关县| 马山县| 稷山县| 米林县| 石狮市| 辽源市| 彩票| 大新县| 晋州市| 无棣县| 商水县| 安福县| 华坪县| 武威市| 潜江市| 安陆市| 高州市| 沂南县| 错那县| 义马市| 秦皇岛市| 宜宾市| 乌海市| 拉萨市| 札达县| 衡阳县| 旬阳县| 增城市| 吉林市| 荔浦县| 镇康县| 张家口市| 宿迁市| 邵阳市|