1. 程式人生 > >spring 自定義註解annotation+aspect 環繞通知配置對dubbo的consumer監控報警

spring 自定義註解annotation+aspect 環繞通知配置對dubbo的consumer監控報警

背景:

對dubbo 的consumer端進行統一監控,實現consumer的統一異常處理、前置provider服務的可用性校驗(若dubobo服務不可以發簡訊提醒)

思路:

(1)自定義annotation,僅作用在類、方法上。減少程式碼耦合性,consumer的類或方法只要增加自定義的註解即可。

(2)猶豫自定義的annotation有可能標註在服務類上,不一定只標註在controller上,所以用springmvc的interceptor有弊端,所以想到用spring的aop的環繞通知進行攔截處理

1.自定義annotation

<span style="font-family:SimSun;font-size:10px;">@Target({ TYPE, METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitor {
    /**
     * 消費的服務
     * @return
     */
    String serviceName() default "";
    /**
     * 服務描述
     * @return
     */
    String desc() default "";
}</span>

1.annotation實現邏輯

<span style="font-family: Arial; font-size: 14px;">  </span><span style="font-family:SimSun;font-size:10px;"> //註解在類上或方法上
                Monitor monitor=mHandler.getMethodAnnotation(Monitor.class);
                if (beanClass.isAnnotationPresent(Monitor.class)||monitor!=null) {
                    String serviceName=monitor.serviceName();
                    if(StringUtils.isNotBlank(serviceName)){
                        EchoService echoService = null;
                        try {
                            echoService = (EchoService) SpringContextUtil.getBean(monitor.serviceName());
                        } catch (Exception e) {
                            log.error("不存在的bean,benName:"+serviceName,e);
                        }
                        try {
                            Object status = echoService.$echo("OK");
                            assert ("OK".equals(status.toString()));
                        } catch (Exception e) {
                            log.error("dubbo 呼叫失敗!請檢查是否存在此服務或dubbo是否正常!serviceName:"+serviceName,e);
                            //傳送簡訊通知 TODO
                        }
                    }
                }</span>


3. Spring AOP

以@AspectJ方式在Spring中實現AOP。由於@Aspect是基於註解的,因此要求支援註解的5.0版本以上的JDK。

要在專案中使用Spring AOP 則需要在專案中匯入除了spring jar包之外,還有aspectjweaver.jar,aspectjrt.jar 和cglib.jar 。

在Spring MVC基本上只需另外加上aspectjweaver.jar和cglib.jar就可以了

[html] view plaincopyprint?
  1. <dependency>
  2.     <groupId>org.aspectj
    </groupId>
  3.     <artifactId>aspectjweaver</artifactId>
  4.     <version>1.7.1</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>cglib</groupId>
  8.     <artifactId>cglib</artifactId>
  9.     <version>2.2.2</version>
  10. </dependency>

好了,前提工作準備完成。


b.環繞增強的@AspectJ程式碼

<span style="font-family:SimSun;font-size:10px;">@Component
@Aspect
public class DubboMonitor {
    @Around(value = "execution(* dubbo.consumer.adapter.*.*(..)) && @annotation(monitor)")
    public Object aroundMethod(ProceedingJoinPoint pjd, Monitor monitor) {
        Object result = null;
        System.out.println(monitor.desc());
        try {
            System.out.println("前置通知");
            result = pjd.proceed();
            System.out.println("後置通知");
        } catch (Throwable e) {
            System.out.println("異常通知");
        }
        System.out.println("返回通知");
        return result;
    }
}</span>
[java] view plaincopyprint?
  1. @Aspect
  2. publicclass ApiAspect {  
  3.     privatestaticfinal Logger logger = LoggerFactory.getLogger("com.xxx.log");  
  4.     //通過within匹配目標方法的class
  5.     @Around("within(com.xxx.api.*Controller)")  
  6.     public String arountAction(ProceedingJoinPoint pjp){  
  7.         //介面request引數檢查,
  8.         HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[0];  
  9.         try {  
  10.             //TODO check
  11.         } catch (Exception e) {  
  12.             //TODO log & return
  13.         }  
  14.         String result = null;  
  15.         try {  
  16.             //執行目標方法
  17.             result = (String) pjp.proceed();  
  18.             //TODO log
  19.         } catch (Throwable e) {  
  20.             //TODO log & return
  21.         }  
  22.         return result;  
  23.     }  
  24. }  
c.Spring xml配置 [html] view plaincopyprint?
  1. <aop:aspectj-autoproxy/>
  2. <beans:beanclass="com.xxx.api.ApiAspect"/>  (可以用@component註解代替此行配置)
  3. <context:component-scanbase-package="com.xxx.api.*"/>

這樣就實現了所需的功能 ,AOP的優點就是對目標方法程式碼不做任何改動,就可以實現前後處理,另外在b中也可以用@Before,@After等其它註解來實現不同的功能,下面就介紹下@AspectJ的詳細用法

4. @AspectJ的詳細用法

在Spring AOP中目前只有執行方法這一個連線點,Spring AOP支援的AspectJ切入點指示符如下:

一些常見的切入點的例子 
execution(public * * (. .))    任意公共方法被執行時,執行切入點函式。 
execution( * set* (. .))   任何以一個“set”開始的方法被執行時,執行切入點函式。 
execution( * com.demo.service.AccountService.* (. .))  當介面AccountService 中的任意方法被執行時,執行切入點函式。 
execution( * com.demo.service.*.* (. .))  當service 包中的任意方法被執行時,執行切入點函式。 within(com.demo.service.*)  在service 包裡的任意連線點。 within(com.demo.service. .*)  在service 包或子包的任意連線點。
this(com.demo.service.AccountService) 實現了AccountService 介面的代理物件的任意連線點。 
target(com.demo.service.AccountService) 實現了AccountService 介面的目標物件的任意連線點。 
args(java.io.Serializable)  任何一個只接受一個引數,且在執行時傳入引數實現了 Serializable 介面的連線點

增強的方式:

@Before:方法前執行

@AfterReturning:執行方法後執行

@AfterThrowing:Throw後執行

@After:無論方法以何種方式結束,都會執行(類似於finally)

@Around:環繞執行

@AspectJ語法基礎
@AspectJ使用JDK 5.0註解和正規的AspectJ 5的切點表示式語言描述切面,由於Spring只支援方法的連線點,所以Spring僅支援部分AspectJ的切點語言。在這節時,我們將對AspectJ切點表示式語言進行必要的學習。
切點表示式函式
    AspectJ 5的切點表示式由關鍵字和操作引數組成,如execution(* greetTo(..))的切點表示式,“execute”為關鍵字,而“* greetTo(..)”為操作引數。在這裡,execute代表目標類執行某一方法,而“* greetTo(..)”是描述目標方法的匹配模式串,兩者聯合起來所表示的切點匹配目標類greetTo()方法的連線點。為了描述方便,我們將 execution()稱作函式,而將匹配串“* greetTo(..)”稱作函式的入參。 
Spring支援9個@ApsectJ切點表示式函式,它們用不同的方式描述目標類的連線點,根據描述物件的不同,可以將它們大致分為4種類型: 
? 方法切點函式:通過描述目標類方法資訊定義連線點; 
? 方法入參切點函式:通過描述目標類方法入參的資訊定義連線點; 
? 目標類切點函式:通過描述目標類型別資訊定義連線點; 
? 代理類切點函式:通過描述目標類的代理類的資訊定義連線點; 
     這4種類型的切點函式,通過表 1進行說明: 
    表 1 切點函式

類別 函式 入參 說明
方法切點函式 execution() 方法 匹配模式串 表示滿足某一匹配模式的所有目標類方法連線點。如execution(* greetTo(..))表示所有目標類中的greetTo()方法。
@annotation() 方法注 解類名 表示標註了特定註解的目標方法連線點。如@annotation(com.baobaotao.anno.NeedTest)表示任何標註了@NeedTest註解的目標類方法。
方法入參切點函式 args() 類名 通過判別目標類方法執行時入參物件的型別定義指定連線點。如args(com.baobaotao.Waiter)表示所有有且僅有一個按型別匹配於Waiter的入參的方法。
@args() 型別注 解類名 通過判別目標方法的執行時入參物件的類是否標註特定註解來指定連線點。如@args(com.baobaotao.Monitorable)表示任何這樣的一個目標方法:它有一個入參且入參物件的類標註@Monitorable註解。
目標類切點函式 within() 類名匹配串    表 示特定域下的所有連線點。如within(com.baobaotao.service.*)表示com.baobaotao.service包中的所有 連線點,也即包中所有類的所有方法,而within(com.baobaotao.service.*Service)表示在 com.baobaotao.service包中,所有以Service結尾的類的所有連線點。
target() 類名    假如目標類按型別匹配於指定類,則目標類的所有連線點匹配這個切點。如通過target(com.baobaotao.Waiter)定義的切點,Waiter、以及Waiter實現類NaiveWaiter中所有連線點都匹配該切點。
@within() 型別註解類名    假如目標類按型別匹配於某個類A,且類A標註了特定註解,則目標類的所有連線點匹配這個切點。    如@within(com.baobaotao.Monitorable)定義的切點,假如Waiter類標註了@Monitorable註解,則Waiter以及Waiter實現類NaiveWaiter類的所有連線點都匹配。
@target() 型別註解類名    目標類標註了特定註解,則目標類所有連線點匹配該切點。如@target(com.baobaotao.Monitorable),假如NaiveWaiter標註了@Monitorable,則NaiveWaiter所有連線點匹配切點。
代理類切點函式 this() 類名  代理類按型別匹配於指定類,則被代理的目標類所有連線點匹配切點。這個函式比較難理解,這裡暫不舉例,留待後面詳解。

@AspectJ 除上表中所列的函式外,還有call()、initialization()、 preinitialization()、 staticinitialization()、 get()、 set()、handler()、 adviceexecution()、 withincode()、 cflow()、 cflowbelow()、 if()、 @this()以及@withincode()等函式,這些函式在Spring中不能使用,否則會丟擲IllegalArgumentException 異常。在不特別宣告的情況下,本書中所講@AspectJ函式均指表 1中所列的函式。


相關推薦

spring 定義註解annotation+aspect 環繞通知配置dubbo的consumer監控報警

背景: 對dubbo 的consumer端進行統一監控,實現consumer的統一異常處理、前置provider服務的可用性校驗(若dubobo服務不可以發簡訊提醒) 思路: (1)自定義annotation,僅作用在類、方法上。減少程式碼耦合性,consumer的

spring --定義註解(配合@Aspect

IT ng- runtime 自定義 alt type cee pan cut 1:首先,聲明自定義註解 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface

spring定義註解(annotation)與AOP中獲取註解

一、自定義註解(annotation) 自定義註解的作用:在反射中獲取註解,以取得註解修飾的類、方法或屬性的相關解釋。 package me.lichunlong.spring.annotation;

spring定義註解(annotation)與獲取註解

註解類自定義 package me.lichunlong.spring.annotation; import java.lang.annotation.Documented;    import j

Json過濾器(基於spring定義註解的方式,欄位進行過濾)

在實際的開發過程中,會經常遇到如下情景: 後臺需要給前端返回JSON資料,但是查詢出來返回的資料裡面有很多屬性是不需要的 本文通過自定義註解的方式進行實現,對response進行攔截,通過註解引數,設定欄位資訊(即,過濾哪些欄位,保留哪些欄位),並將bean自動封裝

SpringBoot定義註解Annotation的使用

      一. 首先匯入相關包, 在build.gradle中新增 dependencies {     //支援AOP     compile('org.springframework.boot:sprin

Android 定義註解(Annotation)

       現在市面上很多框架都有使用到註解,比如butterknife庫、EventBus庫、Retrofit庫等等。也是一直好奇他們都是怎麼做到的,註解的工作原理是啥。咱們能不能自己去實現一個簡單的註解呢。     &nb

初識Spring定義註解的使用

在專案上遇到Spring自定義註解時,一直想搞明白如何使用,今天就找個時間來研究一下…供初學者參考,歡迎大家的指正。 Java5.0定義的元註解: [email protected],     [email protected],     [emai

Spring定義註解載入

在工作中經常使用Spring的相關框架,免不了去看一下Spring的實現方法,瞭解一下Spring內部的處理邏輯。特別是開發Web應用時,我們會頻繁的定義@Controller,@Service等JavaBean元件,通過註解,Spring自動掃描載入了這些元件

【Redis】redis非同步訊息佇列+Spring定義註解+AOP方式實現系統日誌持久化

說明:   SSM專案中的每一個請求都需要進行日誌記錄操作。一般操作做的思路是:使用springAOP思想,對指定的方法進行攔截。拼裝日誌資訊實體,然後持久化到資料庫中。可是仔細想一下會發現:每次的客戶端的每一次請求,伺服器都會處理兩件事情。一個是正常的業務操作;另一個就是我們額外要做的日誌資料記錄。這樣的

spring定義註解的簡單使用案例+ApplicationContextAware介面的使用

  程式碼 註解 @Target({ ElementType.TYPE })//註解用在介面上 @Retention(RetentionPolicy.RUNTIME)//VM將在執行期也保留註釋,因此可以通過反射機制讀取註解的資訊 @Component public @inter

深入Spring:定義註解載入和使用

前言在工作中經常使用Spring的相關框架,免不了去看一下Spring的實現方法,瞭解一下Spring內部的處理邏輯。特別是開發Web應用時,我們會頻繁的定義@Controller,@Service等JavaBean元件,通過註解,Spring自動掃描載入了這些元件,並提供相

spring 定義註解實現登陸攔截

需求:自定義一個註解,使得controller層的類或者方法在寫上這個註解後,會有登陸驗證。實現原理:(1)先寫一個自定義註解,註解上可以通過註釋確定是類/方法可以加此註解。(2)之後,寫一個攔截器,攔截器內可以通過handler得到被攔截器攔截的類或者方法,之後可以通過這個

spring 定義註解實現日誌統一處理

需求:通過註解的方式 統一處理controller和service的日誌(實現上可能不太嚴謹,主要是實現流程)原理:先自定義註解。用aop切面攔截方法的使用,看是否有對應的自定義的註解,如果有,在切面中進行日誌的統一列印,可以獲取到加了註解方法的類名、方法名、引數。如果想每個

Java定義註解Annotation詳解

一:簡介 開發中經常使用到註解,在專案中也偶爾會見到過自定義註解,今天就來探討一下這個註解是什麼鬼,以及註解的應用場景和如何自定義註解。 下面列舉開發中常見的註解 @Override:用於標識該方法繼承自超類, 當父類的方法被刪除或修改了,編譯器會提示錯

深入Spring:定義註解載入和使用 144 作者 wcong 關注 2016.03.23 13:41* 字數 1573 閱讀 7651評論 7喜歡 22 前言 在工作中經常使用Spring的相

前言 在工作中經常使用Spring的相關框架,免不了去看一下Spring的實現方法,瞭解一下Spring內部的處理邏輯。特別是開發Web應用時,我們會頻繁的定義@Controller,@Service等JavaBean元件,通過註解,Spring自動掃描載入了這些元件,並提供相關的服務。 Spring是如

spring定義註解

java註解 即是註釋了,百度解釋:也叫元資料。一種程式碼級別的說明。 個人理解:就是內容可以被程式碼理解的註釋,一般是一個類。 元資料 也叫元註解,是放在被定義的一個註解類的前面 ,是對註解一種限制。 談下這兩個: @Retention 和 @Target   @

自己試驗在spring環繞通知裡獲取目標物件的類名和目標方法的引數類名,用於根據定義註解判斷訪問許可權,有沒有更好的辦法,高手指點一下

public Object doInBusiness(ProceedingJoinPoint pjp) throws Throwable{   Object[] args = pjp.getArgs();   Class[] argsClass = new Class[ar

spring Aspect 實現定義註解的日誌記錄,有時候註解類不起作用的原因分析

使用只要在controller的method上加上@ActionLog(actionGroup = "freeorder",actionType = "update",actionDesc = "操作",insertDb = true)其中insertDb 代表是否插入資料

定義 Java Annotation ,讀取註解

sta tools stp exc num value mage test lang 1. 首先是自定義註解: Java代碼 package cn.veji.hibernate.po; import java.lang.annot