springAOP自定義註解講解

註解:java

能夠看做是對 一個 類/方法 的一個擴展的模版,每一個 類/方法 按照註解類中的規則,來 spring

爲 類/方法 註解不一樣的參數,在用到的地方能夠獲得不一樣的 類/方法 中註解的各類參數 express

與值。 設計模式

註解的原理: 數組

註解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動框架

態代理類。而咱們經過反射獲取註解時,返回的是Java運行時生成的動態代理對象ide

$Proxy1。經過代理對象調用自定義註解(接口)的方法,會最終調用函數

AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中spa

索引出對應的值。而memberValues的來源是Java常量池.net

java.lang.annotation提供了四種元註解,專門註解其餘的註解(在自定義註解的時候,

須要使用到元註解):

@Documented –註解是否將包含在JavaDoc中

@Retention –何時使用該註解

@Target –註解用於什麼地方

@Inherited – 是否容許子類繼承該註解

1.)@Retention– 定義該註解的生命週期

● RetentionPolicy.SOURCE : 在編譯階段丟棄。這些註解在編譯結束以後就再也不有任

何意義,因此它們不會寫入字節碼。@Override, @SuppressWarnings都屬於這類注

解。

● RetentionPolicy.CLASS : 在類加載的時候丟棄。在字節碼文件的處理中有用。註解

默認使用這種方式

● RetentionPolicy.RUNTIME : 始終不會丟棄,運行期也保留該註解,所以可使用

反射機制讀取該註解的信息。咱們自定義的註解一般使用這種方式。

2.)Target – 表示該註解用於什麼地方。默認值爲任何元素,表示該註解用於什麼地

方。可用的ElementType參數包括

● ElementType.CONSTRUCTOR:用於描述構造器

● ElementType.FIELD:成員變量、對象、屬性(包括enum實例)

● ElementType.LOCAL_VARIABLE:用於描述局部變量

● ElementType.METHOD:用於描述方法

● ElementType.PACKAGE:用於描述包

● ElementType.PARAMETER:用於描述參數● ElementType.TYPE:用於描述類、接口(包括註解類型) 或enum聲明

3.)@Documented–一個簡單的Annotations標記註解,表示是否將註解信息添加在java

文檔中。

4.)@Inherited – 定義該註釋和子類的關係

@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承

的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個

annotation將被用於該class的子類。

自定義註解:

自定義註解類編寫的一些規則:

1. Annotation型定義爲@interface, 全部的Annotation會自動繼承

java.lang.Annotation這一接口,而且不能再去繼承別的類或是接口.

2. 參數成員只能用public或默認(default)這兩個訪問權修飾

3. 參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本

數據類型和String、Enum、Class、annotations等數據類型,以及這一些類型的數組.

4. 要獲取類方法和字段的註解信息,必須經過Java的反射技術來獲取 Annotation對象,

由於你除此以外沒有別的獲取註解對象的方法

5. 註解也能夠沒有定義成員, 不過這樣註解就沒啥用了

PS:自定義註解須要使用到元註解

aop的講解

(1)AOP是什麼?AOP與攔截器的區別?

太抽象的不說,若是你知道Struts2的攔截器,攔截器就是應用的AOP的思想,它用於攔截

Action以進行一些預處理或結果處理。而Spring的AOP是一種更通用的模式,能夠攔截

Spring管理的Bean,功能更強大,適用範圍也更廣,它是經過動態代理與反射機制實現的。

( 更 詳 細 的 解 釋 可 參 看 博

客 http://blog.csdn.net/zhangliangzi/article/details/51648032 )

(2)使用AOP須要的一些概念。

1.通知(Advice)

通知定義了在切入點代碼執行時間點附近須要作的工做。

Spring支持五種類型的通知:

Before(前) org.apringframework.aop.MethodBeforeAdvice

after(後)

After-returning(返回後) org.springframework.aop.AfterReturningAdvice

After-throwing(拋出後) org.springframework.aop.ThrowsAdvice

Arround(周圍) org.aopaliance.intercept.MethodInterceptorIntroduction(引入) org.springframework.aop.IntroductionInterceptor

2.鏈接點(Joinpoint)

程序可以應用通知的一個「時機」,這些「時機」就是鏈接點,例如方法調用時、異常

拋出時、方法返回後等等。

3.切入點(Pointcut)

通知定義了切面要發生的「故事」,鏈接點定義了「故事」發生的時機,那麼切入點就

定義了「故事」發生的地點,例如某個類或方法的名稱,Spring中容許咱們方便的用正

則表達式來指定。

4.切面(Aspect)

通知、鏈接點、切入點共同組成了切面:時間、地點和要發生的「故事」。

5.引入(Introduction)

引入容許咱們向現有的類添加新的方法和屬性(Spring提供了一個方法注入的功能)。

6.目標(Target)

即被通知的對象,若是沒有AOP,那麼通知的邏輯就要寫在目標對象中,有了AOP以後它

能夠只關注本身要作的事,解耦合!

7.代理(proxy)

應用通知的對象,詳細內容參見設計模式裏面的動態代理模式。

8.織入(Weaving)

把切面應用到目標對象來建立新的代理對象的過程,織入通常發生在以下幾個時機:

(1)編譯時:當一個類文件被編譯時進行織入,這須要特殊的編譯器才能夠作的到,例

如AspectJ的織入編譯器;

(2)類加載時:使用特殊的ClassLoader在目標類被加載到程序以前加強類的字節代碼;

(3)運行時:切面在運行的某個時刻被織入,SpringAOP就是以這種方式織入切面的,原

理應該是使用了JDK的動態代理技術。

切點表達式

在使用spring框架配置AOP的時候,不論是經過XML配置文件仍是註解的方式都須要定義

pointcut"切入點" 例如定義切入點表達式

expression="execution(* com.fh.service..*.*(..))"

expression="execution(* com.fh.action.login.LoginAction.login(..))"

execution()是最經常使用的切點函數,其語法以下所示: 整個表達式能夠分爲五個部分:

一、execution(): 表達式主體。

二、第一個*號:表示返回類型,*號表示全部的類型。

三、包名:表示須要攔截的包名,後面的兩個句點表示當前包和當前包的全部子包,

com.sample.service.impl包、子孫包下全部類的方法。

四、第二個*號:表示類名,*號表示全部的類。五、*(..):最後這個星號表示方法名,*號表示全部的方法,後面括弧裏面表示方法的參

數,兩個句點表示任何參數。

3、使用AOP的幾種方式

1.經典的基於代理的AOP

2.@AspectJ註解驅動的切面

3.純POJO切面

如何使用

@AspectJ 進行註解配置

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.8.8</version>

</dependency>

1.配置

在springMVC中增長配置

頭部文件中加入

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

2.加入配置

<!-- 開啓註解模式 -->

<aop:aspectj-autoproxy/>

<!-- 掃描註解路徑 -->

<context:component-scan base-package="com.fh.aop" />

3.定義自定義註解接口

 1 @Target({ ElementType.METHOD, ElementType.TYPE })
 2 
 3 @Retention(RetentionPolicy.RUNTIME)
 4 
 5 @Documented
 6 
 7 public @interface ILogAcpect {
 8 
 9 String methodInfo() default "";String modelName() default "";
10 
11 }

4.配置註解版的AOP切面類

  1 @Aspect
  2 
  3 @Component
  4 
  5 public class LogAspect {
  6 
  7 @Pointcut("execution(* com.fh.controller..*.*(..))")
  8 
  9 private void doMethod() {
 10 
 11 }
 12 
 13 @Before("doMethod()")
 14 
 15 public void beforeAdvice(JoinPoint joinPoint) {
 16 
 17 HttpServletRequest request = ((ServletRequestAttributes)
 18 
 19 RequestContextHolder.getRequestAttributes())
 20 
 21 .getRequest();
 22 
 23 // 請求的IP
 24 
 25 String ip = request.getRemoteAddr();
 26 
 27 System.out.println(ip);
 28 
 29 try {
 30 
 31 // 當前訪問的類路徑
 32 
 33 String targetName =
 34 
 35 joinPoint.getTarget().getClass().getName();
 36 
 37 // 當前訪問的方法名
 38 
 39 String methodName = joinPoint.getSignature().getName();
 40 
 41 // 獲取當前類中的公共方法
 42 
 43 Class targetClass = Class.forName(targetName);
 44 
 45 Method[] methods = targetClass.getMethods();
 46 
 47 String params = "";
 48 
 49 if (joinPoint.getArgs() != null &&
 50 
 51 joinPoint.getArgs().length > 0) {
 52 
 53 params = Arrays.toString(joinPoint.getArgs());
 54 
 55 }
 56 
 57 Object[] arguments = joinPoint.getArgs();String logName = "";
 58 
 59 String modelName = "";
 60 
 61 for (Method method : methods) {
 62 
 63 if (method.getName().equals(methodName)) {
 64 
 65 Class[] clazzs =
 66 
 67 method.getParameterTypes();
 68 
 69 if (clazzs.length == arguments.length) {
 70 
 71 if
 72 
 73 (method.getAnnotation(ILogAcpect.class) != null) {
 74 
 75 logName =
 76 
 77 method.getAnnotation(ILogAcpect.class).methodInfo();
 78 
 79 modelName =
 80 
 81 method.getAnnotation(ILogAcpect.class).modelName();
 82 
 83 }
 84 
 85 break;
 86 
 87 }
 88 
 89 }
 90 
 91 }
 92 
 93 // 經過類路徑獲取全部的方法
 94 
 95 System.out.println("日誌輸出的明細爲:" + logName);
 96 
 97 System.out.println("日誌輸出訪問模塊:" + modelName);
 98 
 99 System.out.println("訪問參數:" + params);
100 
101 System.out.println("訪問的類路徑:" + targetName);
102 
103 System.out.println("訪問的方法名:" + methodName);
104 
105 } catch (ClassNotFoundException e) {
106 
107 // TODO Auto-generated catch block
108 
109 e.printStackTrace();
110 
111 }
112 
113 }
114 
115 @After("doMethod()")
116 
117 public void afterAdvice() {
118 
119 System.out.println("afterAdvice");
120 
121 }@AfterThrowing(pointcut = "doMethod()", throwing = "e")
122 
123 public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
124 
125 System.err.println("異常通知:" + e.getMessage());
126 
127 }
128 
129 }
相關文章
相關標籤/搜索