文章目录
- 前言
- 一、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解耦的作用,所以我在测试跑代码时出现了比较多的异常,特别是切入点的路径问题,差点放弃了~~~~还好各种尝试解决嘞
类似这样子的异常