1.AOP是什么
网络上很多解释,本文不在赘述,大致意思就好比,比如你一个月前开发了一个代码,功能就是一个除法功能,而现在,你想在原有除法功能基础上,记录传入的参数(除数,被除数)到数据库,并且在除法功能完成后,记录一下返回值到数据库。按照以前的逻辑是需要到这个除法功能里面,修改原有代码。当然,这个除法功能相对比较简单,修改原有代码不复杂,但是实际生产上的业务肯定是比这个复杂的多,改代码的风险也是不可预计的。在设计模式有一种原则就是开闭原则,对修改关闭,对扩展开放,也是为了规避这一风险,所以spring的Aop很好的做到了这一点。
2.如何使用AOP
引入spring和springAop还有junit的相关jar包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringDemo</groupId>
<artifactId>SpringDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
</dependencies>
</project>
定义配置类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.erwan.cap12.Bean")
public class Cap12MainConfigAop {
@Bean
public Calculator calculator() {
return new Calculator();
}
@Bean
public CalculatorAop calculatorAop() {
return new CalculatorAop();
}
}
其中EnableAspectJAutoProxy注解就是开启AOP功能
//原有代码,提供除法功能的类
public class Calculator {
public int div(final int i, final int j) {
System.out.println("--------");
return i / j;
}
}
定义一个切面类,来扩展Calculator
@Aspect
public class CalculatorAop {
@Around("pointCut()")
public Object AroundCalculator(final ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
System.out.println("@Around:执行目标方法之前...");
Object obj = proceedingJoinPoint.proceed();// 相当于开始执行div
System.out.println("@Arountd:执行目标方法之后...");
return obj;
}
@Before("pointCut()")
public void logBefore(final JoinPoint joinPoint) {
System.out.println("div开始前" + Arrays.asList(joinPoint.getArgs()));
}
@After("pointCut()")
public void logEnd(final JoinPoint joinPoint) {
System.out.println("div开始后" + Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()", throwing = "ex")
public void logException(final Exception ex) {
System.out.println("div发生异常" + ex.getMessage());
}
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(final Object result) {
System.out.println("div返回值" + result);
}
@Pointcut("execution(public * com.erwan.cap12.Bean.Calculator.*(..))")
public void pointCut() {
}
}
测试类:
@Test
public void cap12() {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Cap12MainConfigAop.class);
Calculator bean = context.getBean(Calculator.class);
bean.div(4, 2);
}
测试结果如下:
@Around:执行目标方法之前...
div开始前[4, 2]
Calculator自己运行的div
@Arountd:执行目标方法之后...
div开始后[4, 2]
div返回值2
所以使用aop就以下三步
1,将业务逻辑组件和切面类都加入到容器中, 告诉spring哪个是切面类(@Aspect)
2,在切面类上的每个通知方法上标注通知注解, 告诉Spring何时运行(写好切入点表达式,参照官方文档)
3,开启基于注解的AOP模式 @EableXXXX
SpringAOP可以应用5种类型的通知:
1.前置通知(Before):在目标方法被调用之前调用通知功能。
2.后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
3.返回通知(After-returning):在目标方法成功执行之后调用通知。
4.异常通知(After-throwing):在目标方法抛出异常后调用通知。
5.环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
其中环绕通知比较特殊,他可以在注解的方法体(AroundCalculator)定义是否执行目标方法,如果不执行,则After 和After-returning则不生效,他也可以在捕捉到异常后,重新执行目标方法(div),功能比较强大
其中@Pointcut就是定义需要拦截或者说增强的目标类和目标类的方法,其中 Calculator.*(..)代表 Calculator类的所有方法就是增强所有方法的调用。
使用JoinPoint可以拿到相关的内容, 比如方法名, 参数