1. 程式人生 > >27--Aop知識點回顧

27--Aop知識點回顧

前面的章節,已經分析了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的一些知識點和使用方法做回顧。