文章目錄
- 前言
- 一、XML實作AOP方式
-
- 1.XML配置
- 2.切面通知類的實作
- 3.目标類的實作
- 4.測試實作類
- 5.實作結果
- 6.業務實作
- 二、注解實作AOP方式(AspectJ)
-
- 1.通知實作類(advice)
- 2.通知實作類,附帶請求參數的擷取
- 3.目标類
- 4.測試類
- 5.列印結果
- 總結
前言
提示:實作AOP的方式分為XML方式和注解(AspectJ)實作方式。
一、XML實作AOP方式
1.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 id="TmplController" class="org.example.aop.controller.IndexController"/>
<!-- 聲明通知類 -->
<bean id="aspectBean" class="org.example.aop.config.AopAspect" />
<!-- AOP配置 -->
<aop:config>
<!-- 切入點 -->
<aop:pointcut id="pointcut" expression="execution(* org.example.aop.controller..*(..))"/>
<!--定義通知-->
<aop:aspect ref="aspectBean">
<aop:before method="beforeAspect" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturnAspect" pointcut-ref="pointcut" />
<aop:after method="afterAspect" pointcut-ref="pointcut" />
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
2.切面通知類的實作
代碼如下(示例):
package org.example.aop.config;
import org.aopalliance.intercept.Joinpoint;
/**
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 23:02
*/
public class AopAspect {
//前置操作
public void beforeAspect(){
System.out.println("===前置操縱方法執行===");
}
//後置操作
public void afterAspect(){
System.out.println("===後置操縱方法執行===");
}
//後置最終執行方法
public void afterReturnAspect(){
System.out.println("===後置最終方法執行===");
}
//異常通知:目标方法抛出異常時執行的代碼
public void afterThrowing(){
System.out.println("===========執行異常通知============");
}
}
3.目标類的實作
代碼如下(示例):
package org.example.aop.controller;
/**
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 22:57
*/
public class IndexController {
public void index(){
System.out.println("index");
}
}
4.測試實作類
代碼如下(示例):
package org.example.aop;
import org.example.aop.controller.IndexController;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 23:49
*/
public class TestAop {
@Test
public void index(){
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("aop-config.xml");
IndexController bean = app.getBean(IndexController.class);
bean.index();
}
}
5.實作結果
代碼如下(示例):
===前置操縱方法執行===
index
===後置最終方法執行===
===後置操縱方法執行===
6.業務實作
AOP實作token驗證登陸資訊?
xml配置多個目标類
測試類中增加調用多個目标類的方法:
ArticleController bean2 = app.getBean(ArticleController.class);
bean2.test();
結果:
===前置操縱方法執行===
index
===後置最終方法執行===
===後置操縱方法執行===
===前置操縱方法執行===
===article test=
===後置最終方法執行===
===後置操縱方法執行===
二、注解實作AOP方式(AspectJ)
1.通知實作類(advice)
代碼如下(示例):
package org.example.aop.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* AOP配置類,替代XML檔案配置方式,開啟AOP以及注入需要的bean(類)
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 22:58
*/
//用于定義配置類,替換xml配置檔案
@Configuration
//包掃描,根據需求實作路徑處理 将此路徑下包含注解的類實作bean注入
@ComponentScan(value = "org.example.aop")
//aop開啟
@EnableAspectJAutoProxy
public class AspectConfig {
}
2.通知實作類,附帶請求參數的擷取
代碼如下(示例):
package org.example.aop.config;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 通知實作類
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 23:02
*/
@Aspect //定義切面類
@Component
public class AspectAdvice {
public static final String EXE= "execution(public * org.example.aop.controller..*(..))";
//前置操作
@Before(value = EXE)
public void beforeAspect(JoinPoint joinPoint){
System.out.println("===前置操縱方法執行===");
//處理請求參數
Map<String, Object> param = new HashMap<>();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
for (int i = 0; i < paramValues.length; i++) {
param.put(paramNames[i], paramValues[i]);
}
System.out.println(param);
}
//後置操作
@After(value = EXE)
public void afterAspect(){
System.out.println("===後置操縱方法執行===");
}
//後置最終執行方法
@AfterReturning(value = EXE, returning = "result")
public void afterReturnAspect(){
System.out.println("===後置最終方法執行===");
}
//異常通知:目标方法抛出異常時執行的代碼
@AfterThrowing(value = EXE,throwing = "th")
public void afterThrowing(JoinPoint joinPoint , Exception th){
System.out.println("===========執行異常通知============");
}
}
3.目标類
代碼如下(示例):
package org.example.aop.controller;
import org.springframework.stereotype.Controller;
/**
* 業務實作類(目标類)
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/3 22:57
*/
@Controller
public class IndexController {
public Object index(Object data){
System.out.println("index");
return data;
}
}
4.測試類
代碼如下(示例):
package org.example.aop;
import org.example.aop.config.AspectConfig;
import org.example.aop.controller.ArticleController;
import org.example.aop.controller.IndexController;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author mr.monster
* @version 1.0
* @Description
* @date 2021/5/4 15:20
*/
public class ConfigAopTest {
public class Data{
String a="1";
String b="2";
Integer c =3;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public Integer getC() {
return c;
}
public void setC(Integer c) {
this.c = c;
}
@Override
public String toString() {
return "Data{" +
"a='" + a + '\'' +
", b='" + b + '\'' +
", c=" + c +
'}';
}
}
@Test
public void index(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AspectConfig.class);
IndexController bean = app.getBean(IndexController.class);
Data d = new Data();
bean.index(d);
ArticleController bean1 = app.getBean(ArticleController.class);
bean1.test();
}
}
5.列印結果
代碼如下(示例):
===前置操縱方法執行===
{data=Data{a='1', b='2', c=3}}
index
===後置最終方法執行===
===後置操縱方法執行===
===前置操縱方法執行===
{}
===article test=
===後置最終方法執行===
===後置操縱方法執行===
總結
在學習其他大佬的文章或者視訊是會發現使用了接口類的繼承,我在編碼時直接抛棄接口類的實作是因為,個人認為若通過接口類實作完全失去了AOP解耦的作用,是以我在測試跑代碼時出現了比較多的異常,特别是切入點的路徑問題,差點放棄了~~~~還好各種嘗試解決嘞
類似這樣子的異常