1. 程式人生 > >Spring中AOP開發

Spring中AOP開發

Aop思想

  • servlet技術中的filter過濾器技術
    在這裡插入圖片描述
  • struts2中的interceptor技術
    在這裡插入圖片描述
  • 動態代理
    在這裡插入圖片描述

spring-aop開發概念

spring封裝了代理技術來體現aop思想.
spring可以對所有類進行代理.
spring為了能夠對所有類進行代理.封裝了兩種代理技術

動態代理

侷限性:被帶代理物件必須實現至少一個介面.動態代理技術是基於介面的代理技術
沒有實現介面那麼無法被動態代理.

CGLib代理

屬於繼承代理.該技術生成的代理類是被代理類的子類. 幾乎所有類都可以被CGLIb代理.處了被final修飾的類.

有關aop的名詞解釋

連線點(join point): 所有可以被增強(代理)的方法
切點(point cut):即將(需要)或已經被增強的方法
通知(advice):對切點需要增強的程式碼
目標物件(target):被代理的物件
代理物件(proxy):對目標物件的切點應用通知後生成的物件
織入(weaver)動詞:將通知應用到切點的過程,或者說生成代理物件的過程
切面:(aspect|advisor)組合詞:切點+通知 稱之為切面

aop在spring中的配置

使用xml配置檔案開發

  1. 導包

4+2包+spring-aop包+spring-aspects包 2個在spring輔助包中:aop聯盟包+aspectj-weaver包

  1. 目標物件
    在這裡插入圖片描述
  2. 通知(對切點需要增強的程式碼,一個類)

前置通知 通知程式碼,在目標方法執行前呼叫
環繞通知 通知程式碼,在目標方法執行前和執行後都呼叫
後置通知 通知程式碼,在目標方法執行後呼叫. 切點方法丟擲異常,通知不執行
後置通知 通知程式碼,在目標方法執行後呼叫. 切點方法丟擲異常,通知仍然執行
異常通知 通知程式碼,在目標方法丟擲異常後才會執行.

  1. 配置

1.匯入aop約束,字首為aop
2.註冊目標物件,註冊通知物件
3.在xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
	 
	 <!-- 1.配置目標物件 -->
	 <bean name="userService" class="cn.xiaos.service.UserServiceImpl" ></bean>  
	 <!-- 2.配置通知物件 -->
	 <bean name="myAdvice" class="cn.xiaos.advice.MyAdvice" ></bean>  
	 <!-- 3.配置切面 切點+通知 -->
	 		<!-- 3.1 書寫切點表示式,aspectJ切點表示式
	 				格式 : execution(表示式)
	 					public void cn.itcast.service.UserServiceImpl.save()
	 					void cn.itcast.service.UserServiceImpl.save()  同上
	 					* cn.itcast.service.UserServiceImpl.save() 方法返回值任意
	 					* cn.itcast.service.*ServiceImpl.save() 包中所有以ServiceImpl結尾的類
	 					* cn.itcast.service.*ServiceImpl.*() 方法名任意
	 					* cn.itcast.service.*ServiceImpl.*(..) 沒有或多個任意引數
	 					* cn.itcast.service..*ServiceImpl.*(..) 當前包以及後代包
	 		 -->
	 <aop:config>
	 		<!-- 
	 		aop:pointcut : 配置切點(需要被增強的方法)
	 			 expression:表示式
	 			 id:為表示式指定名稱,方便後續引用	
	 		 -->
	 		 <aop:pointcut expression="execution(* cn.xiaos.service.*ServiceImpl.*(..))" id="myPC"/>
	 		 <!-- 配置通知+切點 => 切面 
	 		 		ref:哪個物件是通知類
	 		 -->
	 		 <aop:aspect ref="myAdvice" >
	 		 	<!-- 前置通知  method=>方法名   pointcut-ref=>切點名稱 -->
	 		 	<aop:before method="before" pointcut-ref="myPC" />
	 		 	<!-- 環繞通知 -->
	 		 	<aop:around method="around" pointcut-ref="myPC" />
	 		 	<!-- 後置通知 -->
	 		 	<aop:after-returning method="afterReturning" pointcut-ref="myPC" />
	 		 	<!-- 後置通知 -->
	 		 	<aop:after method="after" pointcut-ref="myPC" />
	 		 	<!-- 異常通知 -->
	 		 	<aop:after-throwing method="afterThrowing" pointcut-ref="myPC" />
	 		 </aop:aspect>
	 </aop:config>
	   
</beans>
	   

使用註解方式配置

1.導包(同上),2.目標檔案編寫(同上)3.註冊目標物件,註冊通知物件
3.開啟aop註解配置事務開關
<aop:aspectj-autoproxy> </aop:aspectj-autoproxy>
4.在通知類中使用註解配置切面

package cn.xiaos.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

// 5種通知
// 前置通知 通知程式碼,在目標方法執行前呼叫
// 環繞通知 通知程式碼,在目標方法執行前和執行後都呼叫
// 後置通知 通知程式碼,在目標方法執行後呼叫. 切點方法丟擲異常,通知不執行
// 後置通知 通知程式碼,在目標方法執行後呼叫. 切點方法丟擲異常,通知仍然執行
// 異常通知 通知程式碼,在目標方法丟擲異常後才會執行.
//通知類
//@Aspect => 標識當前類用於配置切面
@Aspect 
public class MyAdvice {
	
	@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")
	public void myPC(){}
	
	// 前置通知
	@Before("MyAdvice.myPC()")
	public void before() {
		System.out.println("我是前置通知!");
	}
	// 環繞通知
	@Around("MyAdvice.myPC()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("我是環繞通知前半部分,我在切點方法執行前執行!");
		// 手動呼叫切點方法執行
		Object obj = pjp.proceed(); // 執行切點方法
		System.out.println("我是環繞通知後半部分,我在切點方法執行後執行!");
		return obj;
	}
	// 後置通知 => 出現異常,就不執行
	@AfterReturning("MyAdvice.myPC()")
	public void afterReturning() {
		System.out.println("我是後置通知,出現異常不執行!");
	}
	// 後置通知 => 出現異常,仍然執行
	@After("MyAdvice.myPC()")
	public void after() {
		System.out.println("我是後置通知,出現異常仍然執行!");
	}
	// 異常通知
	@AfterThrowing("MyAdvice.myPC()")
	public void afterThrowing() {
		System.out.println("我是異常通知,丟擲異常後執行!");
	}
}