註解: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 }