首頁 > 軟體

SpringBoot利用切面註解及反射實現事件監聽功能

2022-07-18 18:04:38

前言

當某個事件需要被監聽的時候,我們需要去做其他的事前,最簡單的方式就是將自己的業務 方法追加到該事件之後。

但是當有N多個這樣的需求的時候我們都這樣一個個去新增修改事件的原始碼嗎?

這篇文章將告訴你如何用一個註解,就可以將你的業務程式碼通過切面的方式新增到事件的前後,而不需要修改事件的程式碼

效果圖

如下圖所示,add方法內並沒有呼叫其他的方法,但是其他方法仍然被執行了。

只要給監聽方法加@AddEventListener()註解就可以讓它在事件前後執行了

監聽原理

該方法是利用切面、註解、反射來實現SpringBoot的事件監聽的

1.通過Aspect的切面,切入事件方法

首先使用Aspec的Around(也可以用before或者after,但是比較麻煩)註解,切入AddEvent的方法中,around註解的方法中,可以在事件方法的執行前後新增業務程式碼。但是我們不直接加入需要新增的業務,進入第二步驟。

2.利用反射獲取被AddEventAop註解的類和方法

利用反射Class.forName(class),獲取被AddEventAop註解的類(當然你也可以修改一下,獲取所有的類),該類哪個方法被AddEventListener註解了,就執行該方法,則監聽執行成功。

method.invoke(o, args);

注意(非常重要)

  • AddEventListener使用的類上,必須被AddEventAop註解了,否則反射的時候方法不會被執行。
  • 事件的類必須是bean,否則切面失敗。
  • 監聽方法和(被監聽方法)事件方法的引數數量,型別,順序必須一致,否則可能導致反射執行方法失敗

核心原始碼

@Around("@annotation(event)")
    public Object addEventListener(ProceedingJoinPoint joinPoint, AddEventAop event) throws Throwable {
        Object[] args = joinPoint.getArgs();
        //儲存需要在方法執行之後再執行的類
        List<Method> afterEventMethod = new ArrayList<>();
        //反射獲取AddEventListener修飾的方法並執行
        //獲取自定義註解的設定
        final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(AddEventAop.class);
        for (String key : beans.keySet()) {
            //Spring 代理類導致Method無法獲取,這裡使用AopUtils.getTargetClass()方法
            Object o  = beans.get(key);
            Class<?> aClass = beans.get(key).getClass();
            String name = aClass.getName();
            //aop切面會導致方法註解丟失,在這裡處理獲取原類名
            if (name.contains("$$")){
                String[] names = name.split("\$\$");
                name=names[0];
                aClass = Class.forName(name);
            }
            Method[] methods = aClass.getMethods();
            for (Method method : methods) {
                //獲取指定方法上的註解的屬性
                AddEventListener annotation = method.getAnnotation(AddEventListener.class);
                if (annotation!=null){
                    //執行所有的註解了該類的方法
                    EventType value = annotation.value();
                    if (value.equals(EventType.BEFOREEVENT)){
                        method.invoke(o, args);
                    }else{
                       afterEventMethod.add(method);
                    }
                }
            }
        }
        //執行被切面的方法
        Object proceed = joinPoint.proceed(args);
        //執行需要在方法執行之後再執行的方法
        for (Method method : afterEventMethod) {
            Class<?> aClass = method.getDeclaringClass();
            Object o = aClass.newInstance();
            method.invoke(o, args);
        }
        return proceed;
    }

原始碼地址

Github專案地址

到此這篇關於SpringBoot利用切面註解及反射實現事件監聽功能的文章就介紹到這了,更多相關SpringBoot事件監聽內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com