一 AOP
1.1 什麼是AOP
AOP 面向切面程式設計。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
1.2 AOP底層實作
實際上,AOP 的底層是通過 Spring 提供的的動态代理技術實作的。在運作期間,Spring通過動态代理技術動态的生成代理對象,代理對象方法執行時進行增強功能的介入,在去調用目标對象的方法,進而完成功能的增強。
Spring 架構監控切入點方法的執行。一旦監控到切入點方法被運作,使用代理機制,動态建立目标對象的代理對象,根據通知類别,在代理對象的對應位置,将通知對應的功能織入,完成完整的代碼邏輯運作。
在 Spring 中,架構會根據目标類是否實作了接口來決定采用哪種動态代理的方式。
- 當bean實作接口時,會用JDK代理模式
- 當bean沒有實作接口,用cglib實作( 可以強制使用cglib(在spring配置中加入<aop:aspect jautoproxy proxyt-target-class=”true”/>)
1.3 AOP相關術語
* Target(目标對象):代理的目标對象
* Proxy (代理):一個類被 AOP 織入增強後,就産生一個結果代理類
* Joinpoint(連接配接點):所謂連接配接點是指那些可以被攔截到的點。在spring中,這些點指的是方法,因為 spring隻支援方法類型的連接配接點
* Pointcut(切入點):所謂切入點是指我們要對哪些 Joinpoint 進行攔截的定義
* Advice(通知/ 增強):所謂通知是指攔截到 Joinpoint 之後所要做的事情就是通知 分類:前置通知、後置通知、異常通知、最終通知、環繞通知
* Aspect(切面):是切入點和通知(引介)的結合
* Weaving(織入):是指把增強應用到目标對象來建立新的代理對象的過程。spring采用動态代理織 入,而AspectJ采用編譯期織入和類裝載期織入
1. 編寫核心業務代碼(目标類的目标方法) 切入點
2. 把公用代碼抽取出來,制作成通知(增強功能方法) 通知
3. 在配置檔案中,聲明切入點與通知間的關系,即切面
1.3 基于(xml)AOP開發
- 建立java項目,導入AOP相關坐标
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--導入spring的context坐标,context依賴aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- aspectj的織入(切點表達式需要用到該jar包) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
- 建立目标接口和目标實作類(定義切入點)(略)
- 建立通知類及方法(定義通知) (略)
- 将目标類和通知類對象建立權交給spring (略)
- 在核心配置檔案中配置織入關系,及切面
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--目标類交給IOC容器-->
<bean id="accountServcie" class="com.lagou.servlet.impl.AccountServiceImpl"></bean>
<!--通知類交給IOC容器-->
<bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>
<!--AOP配置-->
<aop:config>
<!--抽取的切點表達式-->
<aop:pointcut id="myPointcut" expression="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
<!--配置切面:切入點+通知-->
<aop:aspect ref="myAdvice">
<!-- <aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>-->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
6.編寫測試代碼(略)
1.4 切點表達式
表達式文法:
execution([修飾符] 傳回值類型 包名.類名.方法名(參數))
execution(public void com.lagou.servlet.impl.AccountServiceImpl.transfer(java.lang.String))
- 通路修飾符可以省略
execution(void com.lagou.servlet.impl.AccountServiceImpl.transfer(java.lang.String))
- 傳回值類型、包名、類名、方法名可以使用星号 * 代替,代表任意
execution(* *.*.*.*.*.*())
- 包名與類名之間一個點 . 代表目前包下的類,兩個點 .. 表示目前包及其子包下的類
execution(* *..*.*())
- 參數清單可以使用兩個點 .. 表示任意個數,任意類型的參數清單
execution(* *..*.*(..))
通路修飾符可以省略
傳回值類型、包名、類名、方法名可以使用星号 * 代替,代表任意
包名與類名之間一個點 . 代表目前包下的類,兩個點 … 表示目前包及其子包下的類
參數清單可以使用兩個點 … 表示任意個數,任意類型的參數清單
切點表達式抽取 :
<!--AOP配置-->
<aop:config>
<!--抽取的切點表達式-->
<aop:pointcut id="myPointcut" expression="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
<!--配置切面:切入點+通知-->
<aop:aspect ref="myAdvice">
<!-- <aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>-->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
1.5 通知類型
1.6 基于注解的AOP開發
- 建立java項目,導入AOP相關坐标 (略)
- 建立目标接口和目标實作類(定義切入點) (略)
- 建立通知類(定義通知) (略)
- 将目标類和通知類對象建立權交給spring (略)
- 在通知類中使用注解配置織入關系,更新為切面類
@Component
@Aspect //更新為切面類,配置切入點和通知關系
public class MyAdvice {
@Before("execution(* com.lagou..*.*(..))")
public void before() {
System.out.println("前置通知...");
}
}
- 在配置檔案中開啟元件掃描和 AOP 的自動代理
<!--元件掃描-->
<context:component-scan base-package="com.lagou"/>
<!--aop的自動代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 編寫測試代碼 (略)
1.8 通知類型
環繞通知:
proceedingJoinPoint.該接口有一個方法proceed()此方法就相當于明确調用切入點方法.
該接口可以作為環繞通知的方法參數,在程式執行時,Spring架構會為我們提供該接口的實作類供我們使用
目前四個通知組合在一起時,執行順序如下:
@Before -> @After -> @AfterReturning(如果有異常:@AfterThrowing)
注解開啟元件掃描和 AOP 的自動代理
@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />
,在程式執行時,Spring架構會為我們提供該接口的實作類供我們使用
目前四個通知組合在一起時,執行順序如下:
@Before -> @After -> @AfterReturning(如果有異常:@AfterThrowing)
注解開啟元件掃描和 AOP 的自動代理
@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />