AOP 概念了解
AOP(Aspect Oriented Programming)面向切面編程,是針對面向對象編程的一種補充,同時也是spring中第二個最核心的功能,例如可以進行權限認證,日志輸出等,可以無侵入的對原來的功能進行切面加入自定義的非業務功能。
- 切面(AspectJ):對橫切關注點的抽象
- 連接點(Joinpoint):被攔截到的點,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
- 通知(Advice):AOP框架在特定的切入點執行的增強處理,分為前置、后置、異常、最終、環繞五種情況
- 切入點(Pointcut):需要攔截的點
- 引入:將方法或字段添加到被處理的類中。Spring允許引入新的接口到任何被處理的對象。例如,你可以使用一個引入,使任何對象實現IsModified接口,以此來簡化緩存
- 目標對象:被AOP框架進行增強處理的對象,也被稱為被增強的對象
- AOP代理:AOP框架創建的對象,簡單的說,代理就是對目標對象的加強。Spring中的AOP代理可以是JDK動態代理,也可以是CGLIB代理
- 織入(Weaving):將增強處理添加到目標對象中,并創建一個被增強的對象的過程。
在spring中AOP代理對象依舊是由IOC容器管理著,在具體代理生成中可以由java動態代理生成也可以由cglib字節碼增強完成,具體運行中會根據具體情況選擇合適的代碼生成方式。如果是接口,則只會使用動態代理生成
在了解完AOP的基礎知識后,介紹AOP的兩種使用方法,XML配置和注解
XML 配置
<bean id="people" class="com.demo.Aop.People" />
<bean id="peopleAop" class="com.demo.Aop.PeopleAop" />
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.demo.Aop.*.*(..))" />
<aop:aspect ref="peopleAop">
<aop:after method="after" pointcut-ref="pc" />
<aop:before method="before" pointcut-ref="pc" />
<aop:around method="around" pointcut-ref="pc" />
<aop:after-returning method="afterReturn" pointcut-ref="pc" />
<aop:after-throwing method="excep" pointcut-ref="pc" />
</aop:aspect>
</aop:config>
public class PeopleAop {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
public Object around(ProceedingJoinPoint pj){
System.out.println("around before");
Object obj = null;
try {
obj = pj.proceed();
} catch (Throwable throwable) {
}
System.out.println("around after");
return obj;
}
public void afterReturn(){
System.out.println("after return");
}
public void excep(){
System.out.println("error!!!!");
}
}
public class People {
public void say() {
System.out.println("chinese");
}
}
最后的執行結果
image.png
看圖得出先后順序是before、around、after、after return。但是xml配置的執行順序就真的是這樣的么?
當我把上面xml配置的before和around換一個位置之后輸出到結果
image.png
結果發生了變化,成為了around、before、after、after return
注解
<bean class="com.demo.Aop.AnimalImpl" id="animal" />
<bean class="com.demo.Aop.AnimalAop" id="animalAop" />
<!-- 上面兩個bean 只是為了便于說明代碼,也可以使用component-scan 配合相關注解完成-->
<aop:aspectj-autoproxy />
<!-- AOP注解核心配置,會生成相關的代理類-->
// 接口類
public interface Animal {
void sleep(String name);
}
// 實現類
public class AnimalImpl implements Animal {
public AnimalImpl() {
System.out.println("init");
}
public void sleep(String name) {
System.out.println(name + " sleep");
}
}
// 切面類
public class AnimalAop {
@Pointcut("execution(* com.demo.Aop.*.*(..))")
public void pointCut(){}
// 定義一個切點,會選擇com.demo.Aop下面所有的類
@Around("pointCut() && args(name)")
public Object around(ProceedingJoinPoint pj, String name){
// 定義為around注解,添加了切點,并且同時加上了參數
Object obj = null;
System.out.println(name + " around before");
try {
obj = pj.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(name + " around after");
return obj;
}
@Before("pointCut() && args(name)")
public void before(String name){
System.out.println(name + " animal before");
}
@After("execution(* com.demo.Aop.*.*(..))")
public void after(){
// 這個直接使用了execution,而沒有使用已經定義好的切點
System.out.println("animal after");
}
}
執行結果
image.png
在原本的實現類實現之后,執行的先后順序為around、before、after、after return
不過這里是沒有XML注解的那種先后執行順序,所有的執行順序都是由spring自身決定的
在當前的demo中可能注意到了,所使用的AnimalImpl是繼承自Animal接口的,如果改成沒有接口的情況呢?
image.png
image.png
很明顯 在使用接口的時候,spring會使用java的動態代理實現,否則會使用cglib實現代理功能
demo基本上就完成了,后面的學習文章會具體分析XML配置和注解配置的實現細節以及同異