一、AOP 配置
1、导入 jar 包
① 导入 Spring 基础包
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-version}</version> </dependency>
② 导入基础的 AOP 包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.3.RELEASE</version> </dependency>
③ 导入加强版的面向切面编程(即使目标对象没有实现任何接口也能创建动态代理)
<dependency> <groupId>org.aspectj</groupId> <artifactId>com.springsource.org.aspectj.weaver</artifactId> <version>1.6.4.RELEASE</version> </dependency> <dependency> <groupId>org.aopalliance</groupId> <artifactId>com.springsource.org.aopalliance</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>net.sourceforge.cglib</groupId> <artifactId>com.springsource.net.sf.cglib</artifactId> <version>2.1.3</version> </dependency>
2、写配置
①将目标类和切面类(封装通知方法(在目标方法执行前后的方法))加入到IOC容器中 ②告诉Spring哪个是切面类@Aspect ③告诉Spring,切面类里面的每一个方法,都是何时何地运行
将业务类添加到容器中:
@Service public class MyMathCalculator implements Calculator{}
将切面类(日志类)加到容器中
/** * 如果将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入 */ @Aspect @Component public class LogUtils { /** * 告诉 Spring 每个方法都什么时候运行 * * try { * @Before * method.invoke(obj, args); * @AfterReturning * }catch(e) { * @AfterThrowing * }finally { * @After * } * * * @Before:在目标方法运行之前 前置通知 * @After:在目标方法运行结束之后 后置通知 * @AfterReturning:在目标方法正常放回之后 返回通知 * @AfterThrowing:在目标方法抛异常之后 异常通知 * @Around:环绕 环绕通知 */ //想在执行目标方法之前 //execution(访问权限符 返回值类 方法签名) @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logStart(){ System.out.println("【XXX】方法执行了,参数为【XXX】"); } //想在目标方法正执行完毕之后 @AfterReturning("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logReturn(){ System.out.println("【XXX】方法执行完成,他的结果为是:"); } @AfterThrowing("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") //想在目标方法出现异常时执行 public static void logException(){ System.out.println("【XXX】方法出现了异常,异常为: "); } //想在目标方法结束时执行 @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logEnd(){ System.out.println("【XXX】方法执行最终完成"); } }
开启包扫描:
<context:component-scan base-package="com.njf.aop"></context:component-scan>
3、在配置文件中 开启基于注解的AOP模式
<!-- 开启基于注解的AOP功能:aop 名称空间 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、测试
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void test1() { //1、从ioc容器中拿到目标对象 //注意:如果想要用类型获取,一定要用他的接口类型,不要用他的本类 Calculator calculator = ioc.getBean(Calculator.class); calculator.add(1, 2); }
二、AspectJ
1、简介
AspectJ:Java社区里最完整最流行的AOP框架。
在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。
2、在 Spring 中启用 AspectJ 注解支持
① 导入jar包依赖
aopalliance.jar aspectj.weaver.jar spring-aspects.jar
② 开启基于注解的 AOP
(1)引入AOP名称空间
(2)配置文件
在配置文件中开启自动生成代理。
<!-- 开启 aspectJ 的自动代理功能 --> <aop:aspectj-autoproxy /> 作用:当 Spring IOC 容器侦测到 bean 配置文件中的 <aop:aspectj-autoproxy> 元素时,会自动为与 AspectJ 切面匹配的 bean 创建代理。
3、用AspectJ注解声明切面
(1)要在 Spring 中声明 AspectJ 切面,只需要在 IOC 容器中将切面声明为 bean 实例; (2)当在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就会为那些与 AspectJ 切面想匹配的 bean 创建代理; (3)在 AspectJ 注解中,切面只是一个带有 @Aspect 注解的 Java 类,它往往包含很多通知;(4)通知是标注有某种注解的简单的 Java 方法;
try{ @Before method.invoke(obj,args); @AfterReturning }catch(e){ @AfterThrowing:在目标方法抛异常之后 }finally{ @after:在目标方法运行结束之后 }
4、切点表达式:
execution(访问权限符 返回值类型 方法签名)
5、通知注解
AspectJ 支持 5 种类型的通知注解: 告诉Spring每个方法,都什么时候运行 ① @Before:前置通知,在方法执行之前执行; ② @After:后置通知,在方法执行之后执行(finally里面,永远都会执行); ③ @AfterRunning:返回通知,在方法返回结果之后执行; ④ @AfterThrowing:异常通知,在方法抛出异常之后执行; ⑤ @Around:环绕通知,围绕这方法执行;
三、完整代码
计算器核心业务:
// 计算器接口 public interface Calculator { public int add(int i, int j); public int sub(int i, int j); public int mul(int i, int j); public int div(int i, int j); } //计算器接口实现类 @Service public class MyMathCalculator implements Calculator{ @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
切面类:
/** * 如果将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入 */ @Aspect @Component public class LogUtils { /** * 告诉 Spring 每个方法都什么时候运行 * * try { * @Before * method.invoke(obj, args); * @AfterReturning * }catch(e) { * @AfterThrowing * }finally { * @After * } * * * @Before:在目标方法运行之前 前置通知 * @After:在目标方法运行结束之后 后置通知 * @AfterReturning:在目标方法正常放回之后 返回通知 * @AfterThrowing:在目标方法抛异常之后 异常通知 * @Around:环绕 环绕通知 */ //想在执行目标方法之前 //execution(访问权限符 返回值类 方法签名) @Before("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logStart(){ System.out.println("【XXX】方法执行了,参数为【XXX】"); } //想在目标方法正执行完毕之后 @AfterReturning("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logReturn(){ System.out.println("【XXX】方法执行完成,他的结果为是:"); } @AfterThrowing("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") //想在目标方法出现异常时执行 public static void logException(){ System.out.println("【XXX】方法出现了异常,异常为: "); } //想在目标方法结束时执行 @After("execution(public int com.njf.aop.calc.MyMathCalculator.add(int, int))") public static void logEnd(){ System.out.println("【XXX】方法执行最终完成"); } }
配置文件:
<!-- 扫描让 IOC 容器管理的 bean --> <context:component-scan base-package="com.njf.aop"></context:component-scan> <!-- 当Spring IOC容器侦测到bean配置文件中的该元素时,会自动为与AspectJ切面匹配的bean创建代理 --> <!-- 开启 aspectJ 的自动代理功能 --> <aop:aspectj-autoproxy />
四、
五、
开启基于注解的AOP功能