springAOP自定義注解講解


注解:

可以看作是對 一個 類/方法 的一個擴展的模版,每個 類/方法 按照注解類中的規則,來

為 類/方法 注解不同的參數,在用到的地方可以得到不同的 類/方法 中注解的各種參數

與值。

注解的原理:

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

態代理類。而我們通過反射獲取注解時,返回的是Java運行時生成的動態代理對象

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

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

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

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()是最常用的切點函數,其語法如下所示: 整個表達式可以分為五個部分:

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

2、第一個*號:表示返回類型,*號表示所有的類型。

3、包名:表示需要攔截的包名,后面的兩個句點表示當前包和當前包的所有子包,

com.sample.service.impl包、子孫包下所有類的方法。

4、第二個*號:表示類名,*號表示所有的類。5、*(..):最后這個星號表示方法名,*號表示所有的方法,后面括弧里面表示方法的參

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

三、使用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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM