1.基本概念
1.1 aop
即面向切面編程,優點是耦合性低,能使業務處理和切面處理分開開發,擴展和修改方面,當引入了注解方式時,使用起來更加方便。
1.2 應用場景
打日志、分析代碼執行時間、權限控制、事務處理、訪問頻率控制、異常處理等等。
1.3 主要概念
幾乎所有涉及aop的地方都會對這些概念進行說明,這里只說說個人的理解,可先了解一下基本概念,然后看完例子之后回頭結合這些概念,才能更深刻的理解。
Aspect:關注點的模塊化。類似於類聲明,包含PointCut和對應的Advice。在Spring AOP中被定義為接口@Aspect,作用於TYPE(類、接口、方法、enum)
JoinPoint:程序執行過程中明確的點,如方法的調用或特定的異常被拋出。常用的是getArgs()用來獲取參數,getTarget()獲得目標對象。
Pointcut:表示一組JoinPoint,這些JoinPoint或是通過邏輯關系組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。 在Spring AOP中被定義為作用於METHOD上的接口@Pointcut
Introduction:添加方法或字段到被通知的類。
Advice: 定義了在 pointcut 里面定義的程序點具體要做的操作,它通過 before、after 和 around 來區別是在每個JoinPoint之前、之后還是代替執行的代碼。
Target Object:包含連接點的對象。也被稱作被通知或被代理對象。POJO
Weaving:組裝方面來創建一個被通知對象。
2.原理淺析
2.1 UML
對於AOP的理解,首先需要看下UML圖,大致有個概念。
2.2 配置文件方式實現aop
如果需要理解一樣東西,首先要會用,再此基礎上理解才會更加深刻。這里給出一個例子,例子原文http://www.cnblogs.com/hongwz/p/5764917.html
這個例子相對比較容易理解一點,TimeHandler是Aspect,"execution(* com.bird.service.impl.PersonServiceBean.*(..))"是PointCut,before/after 是Advice,helloWordImpl1/helloWordImpl2是目標對象。
3. 注解實現
3.1 示例
aop實現一般是針對現有代碼基礎上做一些其他操作,例如下面代碼所示。
這里一切以IOC為基礎
@Aspect修飾類,說明該類是切面關注的抽象,即針對切面目標對象要做什么操作。
@Pointcut針對Spring MVC的RequestMapping和ResponseBody注解(@Iterface)。
@Before、@After、@AfterReturing等針對目標對象相應動作(before、after等)做出相應的操作。
JoinPoint joint 可以獲取目標對象的參數。Object[] argcs= joinPoint.getArgs(); argcs類似於main方法的參數數組,只不過這里需要類型轉換把Object轉換成相應的type。
3.2 實現
這里以限制訪問頻率舉例。在Controller上加上注解,設置參數就可以實現控制用戶的某個時間段內的訪問次數。用到Redis,如果沒有Redis,可以用LocalThread代替。
1. 自定義注解
@Retention(RetentionPolicy.RUNTIME) :
這種類型的Annotations將被JVM保留,所以他們能在運行時被JVM或其他使用反射機制的代碼所讀取和使用。此外RetentionPolicy.SOURCE —— 這種類型的Annotations只在源代碼級別保留,編譯時就會被忽略;RetentionPolicy.CLASS —— 這種類型的Annotations編譯時被保留,在class文件中存在,但JVM將會忽略
@Target
定義注解的作用目標。@Target(ElementType.FIELD)表示該注解可以作用於類或者方法上
@Order
當有多個切面時,Order決定先執行哪個后執行哪個。如果不加Order則默認按照注解標注的先后順序執行。@Order(Ordered.HIGHEST_PRECEDENCE)表示最高優先級。
2.自定義切面
如圖所示@Aspect表示了該類是切面。
@within:用於匹配所以持有指定注解類型內的方法;@annotation(limit) 是匹配含有limit注解的方法。
@Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)") 表示對含有SpringMVC的Controller注解下面的方法 且含有 注解limit的方法有效。
jointPoint獲取HttpServletRequest(被修飾的方法需要有HttpServletRequest參數)
redis/Jedis不熟悉的只需要了解下兩個方法就行:incr方法表示為key值加1,如果key不存在則新建一個key值,並初始化為1。expire表示經過time時間后key會消失。
邏輯是某個Ip地址對某個接口url,在過期時間內如果超過規定的次數就會拋出訪問頻率過高的異常。
3.在需要修飾的對象上加注解使用
4.如果注解沒有生效,檢查下spring配置文件是否配置了aop