一、AOP簡介
AOP是Aspect-Oriented Programming的縮寫,即面向切面編程。利用oop思想,可以很好的處理業務流程,但是不能把系統中某些特定的重復性行為封裝到模塊中。例如,在很多業務中都需要記錄操作日志,結果我們不得不在業務流程中嵌入大量的日志記錄代碼。無論是對業務代碼還是對日志記錄代碼來說,維護都是相當復雜的。由于系統中嵌入了這種大量的與業務無關的其他重復性代碼,系統的復雜性、代碼的重復性增加了。維護起來會更加復雜。
AOP可以很好解決這個問題,AOP關注的是系統的“截面”,在適當的時候“攔截”程序的執行流程,把程序的預處理和后期處理交給某個攔截器來完成。比如,訪問數據庫時需要記錄日志,如果使用AOP的編程思想,那么在處理業務流程時不必在去考慮記錄日志,而是把它交給一個專門的例子記錄模塊去完成。這樣,程序員就可以集中精力去處理業務流程,而不是在實現業務代碼時嵌入日志記錄代碼,實現業務代碼與非業務代碼的分別維護。在AOP術語中,這稱為關注點分離。AOP的常見應用有日志攔截、授權認證、數據庫的事務攔截和數據審計等。
?
二、AOP優點
當一個方法,對不同的用戶的功能要求不滿足時,那么需要在此方法的地方就可以出現變化;在這個變化點進行封轉,留下一個可擴展的接口,便于后期的維護;
?
三、AOP專業名詞
(1)通知(增強)Advice
通知定義了切面是什么以及何時使用,應該應用在某個方法被調用之前?之后?還是拋出異常時?等等。
(2)連接點 Join point
連接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時,拋出異常時,甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程中,并添加新的行為。
(3)切點 Pointcut
切點有助于縮小切面所通知的連接點的范圍。如果說通知定義了切面的“什么”和“何時”的話,那么切點就定義了“何處”,切點會匹配通知所要織入的一個或多個連接點,一般常用正則表達式定義所匹配的類和方法名稱來指定這些切點。
(4)切面 Aspect
切面是通知和切點的結合。通知和切點定義了切面的全部內容——它是什么,在何時何處完成其功能。
(5)引入 Introduction
引入允許我們向現有的類添加新方法或屬性,從而無需修改這些現有類的情況下,讓他們具有新的行為和狀態。
(6)織入 Weaving
在過去我常常把織入與引入的概念混淆,我是這樣來辨別的,“引入”我把它看做是一個定義,也就是一個名詞,而“織入”我把它看做是一個動作,一個動詞,也就是切面在指定的連接點被織入到目標對象中。
?
四、注解方式實現AOP
1、C包下在resources文件夾中創建application2.xml文件,具體內容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:jee="http://www.springframework.org/schema/jee"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd"> <context:component-scan base-package="com.zxc.C"><context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> </context:component-scan><aop:aspectj-autoproxy/> </beans>
?
<context:component-scan base-package="com.zxc.C">用來自動掃描com.zxc.C包中帶有@component注解的bean類,然后將其加載到內存中。
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> 這是aspect切面包的位置。
<aop:aspectj-autoproxy/>用來啟用Spring對@Aspect切面配置的支持。
2、在java類下創建Chinese類,如下:
這個就是測試用的業務代碼,@Componet代表這是個javabean,有xml配置后,自動掃描裝載。
package com.zxc.C; import org.springframework.stereotype.Component; @Component public class Chinese{public String say(String name){//int a=1/0;用來測試異常增強的System.out.println("主方法");System.out.println(name);return "返回值";} }
3、在java類下創建Test類,用來測試代碼:
package com.zxc.C; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test {public static void main(String[] args) {ApplicationContext ctx=new ClassPathXmlApplicationContext("application2.xml");Chinese chinese=(Chinese)ctx.getBean("chinese");chinese.say("環繞增強測試");} }
Application用來生成IoC容器,裝載application2.xml配置文件,之后通過getBean方法來反射創建一個chinese的對象,在調用其核心業務方法say,say的內容是隨意寫的。
4、在java類下創建切面類MyAspect類
package com.zxc.C;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect public class MyAspect {@Before("execution(* com.zxc.C.*.say*(..))")public void ok(){System.out.println("前置增強");}@After("execution(* com.zxc.C.*.say*(..))")public void ok1(){System.out.println("后置增強");}@AfterReturning(pointcut = "execution(* com.zxc.C.*.say*(..))",returning ="myreturn" )public void ok2(Object myreturn){System.out.println(myreturn+"返回增強");}// @AfterThrowing(pointcut ="execution(* com.zxc.C.*.say*(..))",throwing = "myerror") // public void ok3(Throwable myerror){ // System.out.println(myerror+"返回增強"); // } @Around("execution(* com.zxc.C.*.say*(..))")public void ok4(ProceedingJoinPoint pjp){try {System.out.println("環繞點前");Object[] objects=pjp.getArgs();objects[0]=objects[0]+"環繞增強方法";System.out.println(pjp.proceed(objects));System.out.println("環繞點后");} catch (Throwable throwable) {throwable.printStackTrace();}}}
a、增強類型有:前置增強Before、后置增強After、環繞增強Around、異常后增強AfterThrowing、返回增強AfterReturning:用在關注點方法前
優先級:(可以加上@order(num)來標注優先級,數越小優先級越高,1最小)環繞前增強>前置增強>異常增強>返回增強>環繞后增強>后置增強
b、其中環繞增強需要在方法形參上加上形參:ProceedingJoinPoint pjp表示可在切面分鐘執行的連接點,在關注點方法中,加入pjp.proceed()方法,可以運行業務方法。
而在異常增強中需要加上形參Throwable error,用來將業務代碼中的錯誤傳到關注點方法中。
c、切點的書寫規則:(在異常后增強和返回增強中都要加上pointcut)
AspectJ切點指示器
? d、在切面類上要記得加注解@Abstrct,表示這是個切面。
e、jointpoint中的幾個常用方法
?