Spring-AOP(面向切面)
場景模擬(計算器)
功能接口
public interface Calculator {
int add(int i, int j);
int minus(int i, int j);
int multiply(int i, int j);
int div(int i, int j);
}
實現(xiàn)類
public class CalculateLogImpl implements Calculator {
@Override
public int add(int i, int j) {
System.out.println("[日志]add方法開始,參數(shù)是"+ i+" " + j);
int result = i + j;
System.out.println("方法內(nèi)部:resultAdd = " + result);
System.out.println("[日志]add方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int minus(int i, int j) {
System.out.println("[日志]minus 方法開始,參數(shù)是"+ i+" " + j);
int result = i - j;
System.out.println("方法內(nèi)部:resultMinus = " + result);
System.out.println("[日志]minus 方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int multiply(int i, int j) {
System.out.println("[日志]multiply 方法開始,參數(shù)是"+ i+" " + j);
int result = i * j;
System.out.println("方法內(nèi)部:resultMultiply = " + result);
System.out.println("[日志]multiply 方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("[日志]div 方法開始,參數(shù)是"+ i+" " + j);
int result = i / j;
System.out.println("方法內(nèi)部:resultDiv = " + result);
System.out.println("[日志]div 方法結(jié)束,結(jié)果是:" + result);
return result;
}
}
在含有日志輸出的實現(xiàn)類中可以了解到:與核心業(yè)務功能沒有關(guān)系的日志輸出加雜在模塊中,對核心業(yè)務功能有干擾。
思路:解耦
,將附加功能從業(yè)務功能模塊中抽取出來
代理模式
概念
二十三種設計模式中的一種,屬于結(jié)構(gòu)型模式,它的作用就是通過提供一個代理類,讓我們在調(diào)用目標方法時,不再直接對目標方法進行調(diào)用,而是通過代理類間接調(diào)用。讓不屬于目標方法核心邏輯的代碼從目標方法中剝離出來(解耦)。調(diào)用目標方法時先調(diào)用代理對象的方法,減少對目標方法的調(diào)用和打擾,同時讓附加功能能夠集中起來便于管理。
靜態(tài)代理
目標對象
接口
public interface Calculator {
int add(int i, int j);
int minus(int i, int j);
int multiply(int i, int j);
int div(int i, int j);
}
實現(xiàn)類
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("方法內(nèi)部:resultAdd = " + result);
return result;
}
@Override
public int minus(int i, int j) {
int result = i - j;
System.out.println("方法內(nèi)部:resultMinus = " + result);
return result;
}
@Override
public int multiply(int i, int j) {
int result = i * j;
System.out.println("方法內(nèi)部:resultMultiply = " + result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("方法內(nèi)部:resultDiv = " + result);
return result;
}
}
代理類
public class CalculatorStaticProxy implements Calculator {
//被代理的目標對象傳遞過來
private Calculator calculator;
public CalculatorStaticProxy(Calculator calculator) {
this.calculator = calculator;
}
@Override
public int add(int i, int j) {
System.out.println("[日志]add方法開始,參數(shù)是"+ i+" " + j);
//調(diào)用目標對象的方法實現(xiàn)核心業(yè)務
int result = calculator.add(i, j);
System.out.println("[日志]add方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int minus(int i, int j) {
System.out.println("[日志]minus 方法開始,參數(shù)是"+ i+" " + j);
int result = calculator.minus(i, j);
System.out.println("[日志]minus 方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int multiply(int i, int j) {
System.out.println("[日志]multiply 方法開始,參數(shù)是"+ i+" " + j);
int result = calculator.multiply(i,j);
System.out.println("[日志]multiply 方法結(jié)束,結(jié)果是:" + result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("[日志]div 方法開始,參數(shù)是"+ i+" " + j);
int result = calculator.div(i, j);
System.out.println("[日志]div 方法結(jié)束,結(jié)果是:" + result);
return result;
}
}
測試
@Test
public void testStaticProxy(){
Calculator calculator = new CalculatorStaticProxy(new CalculatorImpl());
calculator.add(10, 5);
System.out.println("-------------------");
calculator.minus(10, 5);
System.out.println("-------------------");
calculator.multiply(10, 5);
System.out.println("-------------------");
calculator.div(10, 5);
}
/*
* [日志]add方法開始,參數(shù)是10 5
方法內(nèi)部:resultAdd = 15
[日志]add方法結(jié)束,結(jié)果是:15
-------------------
[日志]minus 方法開始,參數(shù)是10 5
方法內(nèi)部:resultMinus = 5
[日志]minus 方法結(jié)束,結(jié)果是:5
-------------------
[日志]multiply 方法開始,參數(shù)是10 5
方法內(nèi)部:resultMultiply = 50
[日志]multiply 方法結(jié)束,結(jié)果是:50
-------------------
[日志]div 方法開始,參數(shù)是10 5
方法內(nèi)部:resultDiv = 2
[日志]div 方法結(jié)束,結(jié)果是:2
* */
靜態(tài)代理類實現(xiàn)了解耦,但是由于代理類的代碼都是寫死的,就不具備復用的功能,在其他類需要相同功能的類需要進行代理時,也需要重新寫代理類,增加了代碼冗余,解決這一問題需要使用到動態(tài)代理方法。
動態(tài)代理
Proxy工具類
public class ProxyUtil {
//目標對象
private Object target;
public ProxyUtil(Object target) {
this.target = target;
}
//反回代理對象
public Object getProxy(){
//使用Proxy中的newProxyInstance()
/**
* Proxy.newProxyInstance()
* ClassLoader:加載動態(tài)生成代理類的類加載器
* Class<?>[] interfaces:目標對象實現(xiàn)的所有接口的class類型數(shù)組
* InvocationHandler:設置代理對象實現(xiàn)目標對象方法的過程
*/
//ClassLoader:加載動態(tài)生成代理類的類加載器
ClassLoader classLoader = target.getClass().getClassLoader();
//Class<?>[] interfaces:目標對象實現(xiàn)的所有接口的class類型數(shù)組
Class<?>[] interfaces = target.getClass().getInterfaces();
//InvocationHandler:設置代理對象實現(xiàn)目標對象方法的過程
InvocationHandler invocationHandler = new InvocationHandler(){
/**
*
* @param proxy :代理對象
* @param method :需要重寫目標對象的方法
* @param args:method方法中的參數(shù)
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
System.out.println("[動態(tài)代理][日志]" + method.getName() + ", 參數(shù):" + Arrays.toString(args));
//調(diào)用目標的方法
Object result = method.invoke(target, args);
System.out.println("[動態(tài)代理][日志]" + method.getName() + ", 結(jié)果:" + result);
return result;
}
};
return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}
測試類
@Test
public void testProxy(){
//動態(tài)創(chuàng)建代理對象
ProxyUtil proxyUtil = new ProxyUtil(new CalculatorImpl());
Calculator proxy = (Calculator) proxyUtil.getProxy();
proxy.add(1, 2);
System.out.println("---------");
proxy.minus(1, 2);
System.out.println("---------");
proxy.multiply(1, 2);
System.out.println("---------");
proxy.div(1, 2);
}
/*
* [動態(tài)代理][日志]add, 參數(shù):[1, 2]
方法內(nèi)部:resultAdd = 3
[動態(tài)代理][日志]add, 結(jié)果:3
---------
[動態(tài)代理][日志]minus, 參數(shù):[1, 2]
方法內(nèi)部:resultMinus = -1
[動態(tài)代理][日志]minus, 結(jié)果:-1
---------
[動態(tài)代理][日志]multiply, 參數(shù):[1, 2]
方法內(nèi)部:resultMultiply = 2
[動態(tài)代理][日志]multiply, 結(jié)果:2
---------
[動態(tài)代理][日志]div, 參數(shù):[1, 2]
方法內(nèi)部:resultDiv = 0
[動態(tài)代理][日志]div, 結(jié)果:0
* */
AOP概念及相關(guān)術(shù)語
簡介
AOP(Aspect Oriented Programming)是一種設計思想,是軟件設計領域中的面向切面編程,它是面向?qū)ο缶幊痰囊环N補充和完善,它以通過預編譯的方式和運行期動態(tài)代理方式實現(xiàn),在不修改源碼的情況下,給程序動態(tài)統(tǒng)一添加額外功能的一種技術(shù)。利用AOP可以對業(yè)務邏輯的各個部分進行隔離,從而使得業(yè)務邏輯各個部分之間的耦合度降低,提高程序的可重用性,提高開發(fā)效率。
相關(guān)術(shù)語
橫切關(guān)注點
分散在各個模塊中解決同一問題,如用戶驗證、日志管理、事務處理、事務緩存都屬于橫切關(guān)注點
從每個方法中抽取出來的同一類非核心業(yè)務。在同一個項目中,我們可以使用多個橫切關(guān)注點對相關(guān)方法進行多個方面的增強。這個概念不是語法層面的,而是根據(jù)附加功能的邏輯上的需要:有十個附加功能,就有十個橫切關(guān)注點。
通知(增強)
增強,就是想要增強的功能,比如:安全、事務、日志等。每一個橫切關(guān)注點上要做的事情都需要寫一個方法來實現(xiàn),這樣的方法就叫通知方法。
前置通知
:在被代理的目標方法前執(zhí)行返回通知
:在被代理的目標方法成功結(jié)束后執(zhí)行(壽終正寢) 異常通知
:在被代理的目標方法異常結(jié)束后執(zhí)行(死于非命)后置通知
:在被代理的目標方法最終結(jié)束后執(zhí)行(蓋棺定論)環(huán)繞通知
:使用try...catch...finally
結(jié)構(gòu)圍繞整個被代理的目標方法,包括上面四種通知對應的所有位置。
切面
封裝通知方法的類。
目標
被代理的目標對象。
代理
向目標對象應用通知之后創(chuàng)建的代理對象
連接點
這也是一個邏輯概念,不是語法定義的。把方法排成一排,每一個橫切位置看成x軸方向,把方法從上到下執(zhí)行的順序看成y軸,x軸和y軸的交叉點就是連接點。也就是spring允許使用通知的地方。
切入點
定位連接點的方式,每個類的方法中都包含多個連接點,如果把連接點看作數(shù)據(jù)庫中的記錄,那么切入點就是查詢記錄的SQL語句。Spring 的AOP技術(shù)可以通過切入點定位到特定的連接點,即可以使用增強方法的位置。
切入點通過org.springframework.aop.Pointcut
接口進行描述,它使用類和方法作為連接點的查詢條件。
作用
簡化代碼
:把方法中固定位置的重復代碼抽取出來,讓抽取的方法更專注于自己的核心功能,提高內(nèi)聚性。代碼增強
:把特定的功能封裝到切面類中,看哪里有需要,就往上套,被套用了切面邏輯的方法就被切面給增強了
基于注解的AOP
AspectJ
:是AOP思想的一種實現(xiàn)。本質(zhì)上是靜態(tài)代理,將代理邏輯"植入"被代理的目標,編譯得到的字節(jié)碼文件,所以最終效果是動態(tài)的。weaver就是植入器。Spring只是借用了AspectJ中的注解。
動態(tài)代理分類
JDK動態(tài)代理
:有接口,生成接口實現(xiàn)類代理對象,代理對象和目標對象都實現(xiàn)同樣的接口。cglib動態(tài)代理
:沒有接口,繼承目標類,生成子類代理對象
準備工作
引入相關(guān)的依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.9</version>
</dependency>
創(chuàng)建目標資源
接口
public interface Calculator {
int add(int i, int j);
int minus(int i, int j);
int multiply(int i, int j);
int div(int i, int j);
}
實現(xiàn)類
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("方法內(nèi)部:resultAdd = " + result);
return result;
}
@Override
public int minus(int i, int j) {
int result = i - j;
System.out.println("方法內(nèi)部:resultMinus = " + result);
return result;
}
@Override
public int multiply(int i, int j) {
int result = i * j;
System.out.println("方法內(nèi)部:resultMultiply = " + result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("方法內(nèi)部:resultDiv = " + result);
return result;
}
}
配置spring配置文件
<?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/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
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--開啟組件掃描-->
<context:component-scan base-package="com.louis.annotation_aop"></context:component-scan>
<!--開啟aspectJ自動代理,為目標對象生成代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
創(chuàng)建切面類
切入點表達式
語法細節(jié)
用*號代替"權(quán)限修飾符"和"返回值部分"表示"權(quán)限修飾符"和"返回值"不限
包名的部分
①一個"*“號只能代表包的層次結(jié)構(gòu)中的一層,表示這一層是任意的。如:*.com匹配hello.com但不匹配hello.louis.com
②使用”*…"表示任意包名、包的層次深度任意
類名的部分
①類名整體使用*代替,表示類名任意
②可以使用*代替類名的一部分。如:*xxx表示匹配所有名稱以xxx結(jié)尾的類或接口
方法名的部分
①可以使用*代替,表示方法名任意
②可以使用*代替方法名的一部分。如:*xxx表示匹配所有名稱以xxx結(jié)尾的方法
方法參數(shù)列表部分
①可以使用(…)表示任意參數(shù)列表
②可以使用(int,…)表示參數(shù)列表以一個int類型的參數(shù)開頭
③基本數(shù)據(jù)類型和對應的包裝類型是不一樣的(切入點中使用int和實際方法中使用Integer是不匹配的)
方法返回值部分
如果想要明確指定一個返回值類型,那么必須同時寫明權(quán)限修飾符。如:excution(public int…Service.(…,int))
切面類(通知類型)
@Aspect
@Component //表示在spring的ioc容器中進行管理
public class LogAspect {
//設置切入點和通知類型
//通知類型:
// 前置:@Before(value="通過切入點表達式配置切入點")
//切入點表達式:execution(訪問修飾符 增強方法返回類型 方法所在類的全路徑.方法名(參數(shù)列表))
// @Before("execution(* com.louis.annotation_aop.impl.LogAspect.*(..))")
@Before("execution(public int com.louis.annotation_aop.impl.CalculatorImpl.*(..))")
public void beforeMethod(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("前置通知,增強的方法名稱" + name + " , 參數(shù)" + Arrays.toString(args));
}
// 返回:@AfterReturning,返回通知與后置通知有很大的區(qū)別,后置通知在返回通知之后執(zhí)行,返回通知能夠得到目標方法的返回值,使用屬性returning
//它的參數(shù)可以隨便命名,但是切面方法的參數(shù)必須和上面的一致
@AfterReturning(value = "execution(* com.louis.annotation_aop.impl.CalculatorImpl.*(..))", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result){
String name = joinPoint.getSignature().getName();
System.out.println("返回通知, 增強方法名稱" + name + " , 返回結(jié)果" + result);
}
// 異常:@AfterThrowing:目標方法出現(xiàn)異常,這個通知會執(zhí)行,并且能夠獲得目標方法的異常信息
@AfterThrowing(value = "execution(* com.louis.annotation_aop.impl.CalculatorImpl.*(..))", throwing = "Exception")
public void afterThrowingMethod(JoinPoint joinPoint, Throwable Exception){
String name = joinPoint.getSignature().getName();
System.out.println("異常通知, 增強方法名稱" + name + " , 返回結(jié)果" + Exception);
}
// 后置:@After()
@After("execution(public int com.louis.annotation_aop.impl.CalculatorImpl.*(..))")
public void afterMethod(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println("后置通知, 增強方法名稱" + name);
}
// 環(huán)繞:@Around()
@Around("execution(public int com.louis.annotation_aop.impl.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
String argsString = Arrays.toString(args);
Object result = null;
try {
System.out.println("環(huán)繞通知, 目標方法之前執(zhí)行");
//調(diào)用目標方法
result = joinPoint.proceed();
System.out.println("環(huán)繞通知, 目標方法返回值之后執(zhí)行");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("環(huán)繞通知, 目標方法出現(xiàn)異常執(zhí)行");
} finally {
System.out.println("環(huán)繞通知, 目標方法執(zhí)行完畢");
}
return result;
}
}
測試
@Test
public void testAOPAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Calculator calculator = context.getBean(Calculator.class);
calculator.add(1,0);
}
/*
環(huán)繞通知, 目標方法之前執(zhí)行
前置通知,增強的方法名稱add , 參數(shù)[1, 0]
方法內(nèi)部:resultAdd = 1
返回通知, 增強方法名稱add , 返回結(jié)果1
后置通知, 增強方法名稱add
環(huán)繞通知, 目標方法返回值之后執(zhí)行
環(huán)繞通知, 目標方法執(zhí)行完畢
* */
@Test
public void testDiv(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Calculator calculator = context.getBean(Calculator.class);
calculator.div(1,0);
}
/*
環(huán)繞通知, 目標方法之前執(zhí)行
前置通知,增強的方法名稱div , 參數(shù)[1, 0]
異常通知, 增強方法名稱div , 返回結(jié)果java.lang.ArithmeticException: / by zero
后置通知, 增強方法名稱div
環(huán)繞通知, 目標方法出現(xiàn)異常執(zhí)行
環(huán)繞通知, 目標方法執(zhí)行完畢
* */
基于注解的AOP
重用切入點和切面優(yōu)先級
重用切入點
//重用切入點表達式,定義一個方法,之后在需要切入點的時候直接調(diào)用這個方法
/*
* 在同一個類下,可以直接使用:@Before("pointcut()")
* 在不同的類中,需要加入類的路徑: @Before("com.louis.annotation_aop.impl.LogAspect.pointcut()")
* */
@Pointcut(value = "execution(public int com.louis.annotation_aop.impl.CalculatorImpl.*(..))")
public void pointcut(){
}
切面優(yōu)先級
相同目標方法上同時存在多個切面時,切面的優(yōu)先級控制切面的內(nèi)外嵌套順序
優(yōu)先級高的切面在外面,優(yōu)先級低的切面在里面。
使用@Order注解可以控制切面的優(yōu)先級
@Order(較小的數(shù)):優(yōu)先級高
@Order(較大的數(shù)):優(yōu)先級低文章來源:http://www.zghlxwxcb.cn/news/detail-602769.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-602769.html
切面類
@Component //表示在spring的ioc容器中進行管理
public class LogAspect {
//前置通知
public void beforeMethod(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("前置通知,增強的方法名稱" + name + " , 參數(shù)" + Arrays.toString(args));
}
// 返回通知
public void afterReturningMethod(JoinPoint joinPoint, Object result){
String name = joinPoint.getSignature().getName();
System.out.println("返回通知, 增強方法名稱" + name + " , 返回結(jié)果" + result);
}
// 異常通知
public void afterThrowingMethod(JoinPoint joinPoint, Throwable Exception){
String name = joinPoint.getSignature().getName();
System.out.println("異常通知, 增強方法名稱" + name + " , 返回結(jié)果" + Exception);
}
// 后置通知
public void afterMethod(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println("后置通知, 增強方法名稱" + name);
}
// 環(huán)繞通知
public Object aroundMethod(ProceedingJoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
String argsString = Arrays.toString(args);
Object result = null;
try {
System.out.println("環(huán)繞通知, 目標方法之前執(zhí)行");
//調(diào)用目標方法
result = joinPoint.proceed();
System.out.println("環(huán)繞通知, 目標方法返回值之后執(zhí)行");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("環(huán)繞通知, 目標方法出現(xiàn)異常執(zhí)行");
} finally {
System.out.println("環(huán)繞通知, 目標方法執(zhí)行完畢");
}
return result;
}
//重用切入點表達式,定義一個方法,之后在需要切入點的時候直接調(diào)用這個方法
/*
* 在同一個類下,可以直接使用:@Before("pointcut()")
* 在不同的類中,需要加入類的路徑: @Before("com.louis.annotation_aop.impl.LogAspect.pointcut()")
* */
@Pointcut(value = "execution(public int com.louis.xml_aop.impl.CalculatorImpl.*(..))")
public void pointcut(){
}
}
配置文件beanaop.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/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
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--開啟組件掃描-->
<context:component-scan base-package="com.louis.xml_aop"></context:component-scan>
<!--配置aop五種通知類型-->
<aop:config>
<!--配置切面類-->
<aop:aspect ref="logAspect">
<!--配置切入點-->
<aop:pointcut id="pointcut" expression="execution(* com.louis.xml_aop.impl.CalculatorImpl.*(..))"/>
<!--配置五種通知類型-->
<!--前置通知-->
<aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before>
<!--后置通知-->
<aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
<!--返回通知-->
<aop:after-returning method="afterReturningMethod" returning="result" pointcut-ref="pointcut"></aop:after-returning>
<!--異常通知-->
<aop:after-throwing method="afterThrowingMethod" throwing="Exception" pointcut-ref="pointcut"></aop:after-throwing>
<!--環(huán)繞通知-->
<aop:around method="aroundMethod" pointcut-ref="pointcut"></aop:around>
</aop:aspect>
</aop:config>
</beans>
測試
@Test
public void testAOPXMLAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("beanaop.xml");
Calculator calculator = context.getBean(Calculator.class);
calculator.add(1,0);
}
/*
前置通知,增強的方法名稱add , 參數(shù)[1, 0]
環(huán)繞通知, 目標方法之前執(zhí)行
方法內(nèi)部:resultAdd = 1
環(huán)繞通知, 目標方法返回值之后執(zhí)行
環(huán)繞通知, 目標方法執(zhí)行完畢
返回通知, 增強方法名稱add , 返回結(jié)果1
后置通知, 增強方法名稱add
* */
到了這里,關(guān)于Spring-AOP(面向切面)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!