27--Aop知識點回顧
阿新 • • 發佈:2018-12-16
前面的章節,已經分析了IoC容器的原始碼,接下來的章節來分析Spring的另一個核心功能AOP。為了更好的分析原始碼,需要先溫習一個AOP的知識點。
1.先來回顧一下AOP中的一些術語。
- 連線點(Jointpoint):表示需要在程式中插入橫切關注點的擴充套件點,連線點可能是類初始化、方法執行、方法呼叫、欄位呼叫或處理異常等等,Spring只支援方法執行連線點,在AOP中表示為“在哪裡幹”;
- 切入點(Pointcut):選擇一組相關連線點的模式,即可以認為連線點的集合,Spring支援perl5正則表示式和AspectJ切入點模式,Spring預設使用AspectJ語法,在AOP中表示為“在哪裡乾的集合”;
- 通知(Advice):在連線點上執行的行為,通知提供了在AOP中需要在切入點所選擇的連線點處進行擴充套件現有行為的手段;包括前置通知(before advice)、後置通知(after advice)、環繞通知(around advice),在Spring中通過代理模式實現AOP,並通過攔截器模式以環繞連線點的攔截器鏈織入通知;在AOP中表示為“幹什麼”;
- 方面/切面(Aspect):橫切關注點的模組化,比如上邊提到的日誌元件。可以認為是通知、引入和切入點的組合;在Spring中可以使用Schema和@AspectJ方式進行組織實現;在AOP中表示為“在哪乾和幹什麼集合”;
- 引入(inter-type declaration):也稱為內部型別宣告,為已有的類新增額外新的欄位或方法,Spring允許引入新的介面(必須對應一個實現)到所有被代理物件(目標物件), 在AOP中表示為“幹什麼(引入什麼)”;
- 目標物件(Target Object):需要被織入橫切關注點的物件,即該物件是切入點選擇的物件,需要被通知的物件,從而也可稱為“被通知物件”;由於Spring AOP 通過代理模式實現,從而這個物件永遠是被代理物件,在AOP中表示為“對誰幹”;
- AOP代理(AOP Proxy):AOP框架使用代理模式建立的物件,從而實現在連線點處插入通知(即應用切面),就是通過代理來對目標物件應用切面。在Spring中,AOP代理可以用JDK動態代理或CGLIB代理實現,而通過攔截器模型應用切面。
- 織入(Weaving):織入是一個過程,是將切面應用到目標物件從而創建出AOP代理物件的過程,織入可以在編譯期、類裝載期、執行期進行。
2.非註解方式
- bean
package com.lyc.cn.v2.day04;
public class AopTestBean {
public void test() {
System.out.println("--被增強的方法");
}
}
- 切面類
package com.lyc.cn.v2.day04;
public class MyAspect {
public void beforeAdvice() {
System.out.println("前置通知");
}
public void afterAdvice() {
System.out.println("後置通知");
}
}
- 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: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">
<!-- bean -->
<bean id="aopTestBean" class="com.lyc.cn.v2.day04.AopTestBean"/>
<!-- 切面類-->
<bean id="aspect" class="com.lyc.cn.v2.day04.MyAspect"/>
<aop:config>
<!-- 切入點-->
<aop:pointcut id="pointcut" expression="execution(* com.lyc.cn.v2.day04..*.*(..))"/>
<aop:aspect ref="aspect">
<!--通知-->
<aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
<aop:after method="afterAdvice" pointcut="execution(* com.lyc.cn.v2.day04..*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
- 測試用例
package com.lyc.cn.v2.day04;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1() {
// 非註解方式aop
ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day04.xml");
AopTestBean aopTestBean = ctx.getBean("aopTestBean", AopTestBean.class);
aopTestBean.test();
}
}
- 結果
前置通知
--被增強的方法
後置通知
3.註解方式
- 切面類
package com.lyc.cn.v2.day04;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class AspectJTest {
/**
* 例如:execution (* com.sample.service.impl..*.*(..))
* 1、execution(): 表示式主體。
* 2、第一個*號:表示返回型別,*號表示所有的型別。
* 3、包名:表示需要攔截的包名,後面的兩個點表示當前包和當前包的所有子包,
* 即com.sample.service.impl包、子孫包下所有類的方法。
* 4、第二個*號:表示類名,*號表示所有的類。
* 5、*(..):最後這個星號表示方法名,*號表示所有的方法,後面括弧裡面表示方法的引數,兩個點表示任何引數。
**/
@Pointcut("execution(* com.lyc.cn.v2.day04..*.*(..))")
public void test() {
}
@Before("test()")
public void beforeTest() {
System.out.println("--前置通知");
}
@After("test()")
public void afterTest() {
System.out.println("--後通通知");
}
@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
System.out.println("--環繞通知開始");
Object o = null;
try {
o = p.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("--環繞通知結束");
return o;
}
}
- 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: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">
<aop:aspectj-autoproxy/>
<bean id="aopTestBean" class="com.lyc.cn.v2.day04.AopTestBean"></bean>
<bean class="com.lyc.cn.v2.day04.AspectJTest"></bean>
</beans>
- 測試用例
package com.lyc.cn.v2.day04;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test2() {
// 註解方式AOP
ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day05.xml");
AopTestBean aopTestBean = ctx.getBean("aopTestBean", AopTestBean.class);
aopTestBean.test();
}
}
- 結果
--環繞通知開始
--前置通知
--被增強的方法
--環繞通知結束
--後通通知
4.總結
本節主要對AOP的一些知識點和使用方法做回顧。