AOP概念
1、AOP:面向切面(方面)編程,擴展功能不修改源代碼實現
AOP原理
AOP采用橫向抽取機制,取代了傳統縱向繼承體系重復性代碼
傳統的縱向抽取機制:
橫向抽取機制:
AOP操作術語
1、Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在Spring中這些點指的是方法,因為Spring只支持方法類型的連接點。
——即類里面可以被增強的方法,這些方法被稱為連接點。
2、Pointcut(切入點):所謂切入點是指我們要對那些 Joinpoint 進行攔截的定義
——在類中,實際被增強的方法就是切入點。(即連接點不一定是切入點,而切入點一定是連接點)
3、Advice(通知 / 增強):所謂通知是指攔截到 Joinpoint 之后所要做的事情就是通知,通知分為前置通知、后置通知、異常通知、最終通知、環繞通知(切面要完成的功能)
-
- 前置通知:在方法之前執行
- 后置通知:在方法之后執行
- 異常通知:方法出現異常執行
- 最終通知:在后置通知之后執行
- 環繞通知:在方法之前和之后執行
4、Aspect(切面):是切入點和通知(或引介)的結合
——把增強應用到具體方法(切入點)的過程稱為切面。
5、Target(目標對象):代理的目標對象(要增強的方法所在的類)
6、Weaving(織入):是把增強應用到目標的過程,把 advice 應用到 target 的過程
7、Proxy(代理):一個類被AOP織入增強后,就產生一個結果代理類
8、Introduction(引介):引介是一種特殊的通知,在不修改類代碼的前提下,Introduction 可以在運行期為類動態地添加一些方法或 Field
Spring中的AOP操作原理
1、在Spring里面進行AOP操作,使用 AspectJ 實現
(1)AspectJ 不是 Spring 一部分,和 Spring 一起使用進行 AOP 操作
(2)Spring2.0以后就新增了對 AspectJ 切點表達式的支持
(3)@AspectJ 是 AspectJ1.5 新增功能,通過 JDK5 注解技術,允許直接在Bean類中定義切面
(4)新版本的 Spring 框架,建議使用 AspectJ 來開發 AOP
2、使用 AspectJ 實現 AOP 有兩種方式
(1)基於 AspectJ 的xml配置
(2)基於 AspectJ 的注解方式
Spring中AOP操作的准備工作
1、引入Jar包(Maven項目)
<dependencies>
<!-- 引入一個spring-context 會自動依賴 spring-core、spring-beans、spring-expression 三個核心包 以及spring-aop、aopalliance 兩個aop相關jar包 和commons-logging 一個日志相關jar包 我們引入一個spring-context 會自動引入6個依賴jar (context是真核心!!) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<!-- 引入spring-aspects的jar包 會自動引入依賴的 aspectjweaver 的jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
MavenDependencies
2、創建Spring核心配置文件,導入 AOP 的約束
使用表達式配置切入點
1、切入點:實際增強的方法
2、常用的表達式
execution(<訪問修飾符>?<返回值類型><方法名>(參數)<異常>)
(1)execution(* com.bjxb.aop.Book.add(..))——星號代表匹配所有的訪問修飾符(注意第一個星號后需要加空格),add(..)中的點代表可以有參數
(2)execution(* com.bjxb.aop.Book.*(..))——第二個星號代表Book類中所有的方法
(4)execution(* com.bjxb.aop. . *(..))——第二個星號前面的兩個點代表該包、及其子包下所有的類,一個點不包含其子包
(5)execution(* *.*(..))——第二個星號代表所有的類
(6)execution(* save*(..))——匹配所有的save開頭的方法
AspectJ 的 AOP操作
1、被增強類(目標對象和切入點)
public class Book { public void add() { System.out.println("add.........."); } }
2、增強類(通知 / 增強)
public class MyBook { public void before1() { System.out.println("前置增強........"); } public void after1() { System.out.println("后置增強......."); } // 環繞通知
public void around1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 方法之前
System.out.println("方法之前........."); // 執行被增強的方法
proceedingJoinPoint.proceed(); // 方法之后
System.out.println("方法之后........."); } }
3、配置文件applicationContext.xml
<!-- 1.配置對象 -->
<bean id="book" class="com.bjxb.aop.Book"></bean>
<bean id="myBook" class="com.bjxb.aop.MyBook"></bean>
<!-- 2.配置AOP操作 -->
<aop:config>
<!-- 2.1配置切入點 -->
<aop:pointcut expression="execution(* com.bjxb.aop.Book.*(..))" id="pointcut1"/>
<!-- 2.2配置切面 把增強用到方法上面 -->
<aop:aspect ref="myBook">
<!-- 配置增強類型 method:增強類中使用哪個方法作為前置 -->
<aop:before method="before1" pointcut-ref="pointcut1"/>
<aop:after method="after1" pointcut-ref="pointcut1"/>
<aop:around method="around1" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>