一、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.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://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中的幾個常用方法