Spring框架實現AOP的兩種實現方式

Spring AOP

概念

  1. 面向切面編程,擴展功能不需修改源代碼
  2. AOP採用橫向抽取機制,取代了縱向抽取機制
  3. 在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想

AOP和OOP的關係

  1. AOP面向切面編程,而OOP面向對象編程
  2. AOP是對OOP的一種補充,而不是對立關係

AOP的演變

從縱向抽取機制–>橫向抽取機制

AOP底層使用動態代理方式實現

第一種情況:有接口,使用JDK動態代理方式創建接口實現類的代理對象
第二種情況:沒有接口,使用cglib創建類的子類代理對象

總結

  1. 函數本身只需要實現業務邏輯即可
  2. 散落在各個功能方法上卻和業務邏輯無關的功能可以封裝起來,形成一個橫切關注點(橫切面)

AOP術語

  1. 連接點:類中可以被增強的方法,這些方法稱爲連接點
  2. 切入點:實際增強的方法稱爲切入點
  3. Advice(通知/增強):增強的邏輯稱爲增強,比如擴展日誌功能,日誌功能的邏輯就稱爲增強
分類 含義
前置通知 在方法之前執行
後置通知 在方法之後執行
異常通知 方法出現異常
最終通知 在後置之後執行
環繞通知 在方法之前和之後執行
  1. 切面:把具體增強的邏輯應用到具體執行的方法上面的過程,稱爲切面
    把增強用到切入點的過程

Spring實現AOP的操作

在Spring中進行aop操作,需要依賴aspectJ實現

基於aspectJ實現aop通過xml配置方式

一. 步驟

  1. 導入aop相關的jar
  2. 創建核心配置文件,導入AOP約束
  3. 準備增強類和被增強類(指定切入點和通知)
  4. 使用表達式配置切入點
    二. 常用的表達式(使用表達式目的是配置切入點,完成方法的增強)
    execution(<訪問修飾符>?<返回類型><方法名>(<參數>)<異常>),
  5. 訪問修飾符:可以是public或者private 通常情況可以指定*,代表是任意的訪問修飾符
  6. 方法的全路徑:是增強方法的全路徑,表示對這個路徑下的類中的方法做增強,可以在類的後面加上*,表示對所有方法做增強
    eg:execution(* com.hpe.aop.Book.* (…))
    也可以匹配以XX開頭的方法做增強execution(* save* (…)):以save開頭的方法都能做增強
    三. 使用xml配置切面,實現前置通知
    Book.java
// 被增強類
public class Book {
	
	// 切入點
	public void add(){
		System.out.println("add...");
	}
	
	// 連接點(也是切入點)
	public void delete(){
		System.out.println("delete...");
	}
}

MyAdvice.java

// 增強類
public class MyAdvice {

	// 前置通知
	public void doBefore(){
		System.out.println("前置增強...");
	}
	
	// 後置通知
	public void doAfter(){
		System.out.println("後置增強...");
	}
	
	// 環繞通知 ProceedingJoinPoint:用來調用被增強的方法
	public void doAround(ProceedingJoinPoint p) throws Throwable{
		// 方法之前
		System.out.println("方法之前...");
		// 執行被增強的方法
		p.proceed();
		// 方法之後
		System.out.println("方法之後...");
	}
}

applicationContext.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:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 1.配置對象(被增強類和增強類) -->	
	<bean id="book" class="com.hpe.aop.Book"></bean>
	<bean id="myAdvice" class="com.hpe.aop.MyAdvice"></bean>
	<!-- 2.配置aop操作 -->
	<aop:config>
		<!-- 2.1配置切入點(指定對哪些方法做增強) -->
		<aop:pointcut expression="execution(* com.hpe.aop.Book.add(..))" id="pointcut1"/>
		<aop:pointcut expression="execution(* com.hpe.aop.Book.delete(..))" id="pointcut2"/>
		<!-- 2.2配置切面(把增強應用到具體的切入點) ref:增強的對象-->
		<aop:aspect ref="myAdvice">
			<!-- 增強的類型 method:增強使用哪個方法作爲前置通知 pointcut-ref:把增強應用到哪個切入點上面 -->
			<aop:before method="doBefore" pointcut-ref="pointcut1"/>
			<!-- 後置通知 -->
			<aop:after-returning method="doAfter" pointcut-ref="pointcut1"/>
			<!-- 環繞通知 -->
			<aop:around method="doAround" pointcut-ref="pointcut2"/>
		</aop:aspect>
	</aop:config>	
</beans>

測試類

// 使用XML配置方式實現前置、後置通知做方法增強
@Test
public void test2(){
	// 1.讀取配置文件
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	// 2.獲得對象
	Book book = (Book) context.getBean("book");
	// 3.訪問方法
	book.add();
}

// 使用XML配置方式實現環繞通知做方法增強
@Test
public void test3(){
	// 1.讀取配置文件
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	// 2.獲得對象
	Book book = (Book) context.getBean("book");
	// 3.訪問方法
	book.delete();
}
基於aspectJ實現aop通過註解方式
AOP相關的註解
註解 含義
@Aspect 註解在類上面,聲明一個切面
@Pointcut 註解在方法上面,聲明一個切入點,況且要指定aspect表達式
@Before 前置通知
@After @AfterReturning後置通知,@AfterThrow異常通知
@Round 環繞通知
代碼實例

被增強類Person.java

// 被增強類(被代理對象)
@Component(value="person")
public class Person {
	
	public void eat(){
		System.out.println("eat...");
	}
	
	public void drink(){
		System.out.println("drink...");
	}
}

增強類MyAspect.java

// 增強類
// 3.在增強類上使用註解
@Component
@Aspect
public class MyAspect {
	
	// 在方法上面使用註解來配置通知
	// Before:前置通知;value:切入點(表達式)
	@Before(value="execution(* com.hpe.aop.Person.eat(..))")
	public void doBefore(){
		System.out.println("前置增強...");
	}
	
	@After(value="execution(* com.hpe.aop.Person.drink(..))")
	public void doAfter(){
		System.out.println("後置增強...");
	}
	
}

applicationContext2.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:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- 1.創建對象 -->	
	<!-- <bean id="person" class="com.hpe.aop.Person"></bean>
	<bean id="myAspect" class="com.hpe.aop.MyAspect"></bean> -->
	<!-- 開啓註解掃描 -->
	<context:component-scan base-package="com.hpe.aop"></context:component-scan>
	<!-- 2.使用註解的方式開啓AOP的操作:開啓註解掃描 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

Test.java

// 使用註解方式實現環繞通知做方法增強
@Test
public void test4(){
	// 1.讀取配置文件
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
	// 2.獲得對象
	Person person = (Person) context.getBean("person");
	// 3.訪問方法
	person.eat();
	person.drink();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章