1. 说明
AOP能够给组件创建代理类,在目标类的方法的前后,异常等位置织入自定义代码,到达方法增强的目的;
2. 步骤
2.1 编写业务类;
2.2 编写业务切面类,在目标业务类的目标方法的适当位置(方法之前、方法运行结束、方法出现异常)编写自定义代码;
通知方法:
前置通知(@Before):在目标方法运行之前运行
后置通知(@After)::在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
2.3 给切面类的目标方法标注何时何地运行(通知注解);
2.4 将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
2.5 给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
3. 例子
- 3.1 业务类
package com.yibai.spring.annotation.aop;
public class Calculator {
public int div(int a, int b) {
return a / b;
}
}
- 3.2 业务切面类
package com.yibai.spring.annotation.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CalculatorAspect {
@Pointcut(value = "execution(public int com.yibai.spring.annotation.aop.Calculator.*(..))")
public void pointCutCalculator() {
}
@Before("pointCutCalculator()")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@Before ... 方法名: " + methodName + ", 方法参数: " + Arrays.asList(args));
}
@After("pointCutCalculator()")
public void after(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@After ... 方法名: " + methodName + ", 方法参数: " + Arrays.asList(args));
}
// returning: 接收返回值
@AfterReturning(value = "pointCutCalculator()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println(
"@AfterReturning ... 方法名: " + methodName + ", 方法参数: " + Arrays.asList(args) + ", 正常返回值: " + result);
}
// throwing: 接收异常信息
@AfterThrowing(value = "pointCutCalculator()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println("@AfterThrowing ... 方法名: " + methodName + ", 方法参数: " + Arrays.asList(args) + ", 异常信息: " + e);
}
}
- 3.3 主配置类
package com.yibai.spring.annotation.main.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.yibai.spring.annotation.aop.Calculator;
import com.yibai.spring.annotation.aop.CalculatorAspect;
@EnableAspectJAutoProxy //开启基于注解的aop模式
public class MainConfigForAop {
@Bean
public Calculator calculator() {
return new Calculator();
}
@Bean
public CalculatorAspect calculatorAspect() {
return new CalculatorAspect();
}
}
- 3.4 启动类
package com.yibai.spring.annotation.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.yibai.spring.annotation.aop.Calculator;
import com.yibai.spring.annotation.main.config.MainConfigForAop;
/**
* Hello world!
*
*/
public class MainClass {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
MainConfigForAop.class);
Calculator calculator = applicationContext.getBean(Calculator.class);
System.out.println("结果: " + calculator.div(10, 2));
applicationContext.close();
}
}
- 3.5 运行打印结果
@Before ... 方法名: div, 方法参数: [10, 2]
@After ... 方法名: div, 方法参数: [10, 2]
@AfterReturning ... 方法名: div, 方法参数: [10, 2], 正常返回值: 5
结果: 5
当运行 10/0 的打印结果
@Before ... 方法名: div, 方法参数: [10, 0]
@After ... 方法名: div, 方法参数: [10, 0]
@AfterThrowing ... 方法名: div, 方法参数: [10, 0], 异常信息: java.lang.ArithmeticException: / by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.yibai.spring.annotation.aop.Calculator.div(Calculator.java:6)
at com.yibai.spring.annotation.aop.Calculator$$FastClassBySpringCGLIB$$ef7d340d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.yibai.spring.annotation.aop.Calculator$$EnhancerBySpringCGLIB$$bcd84541.div(<generated>)
at com.yibai.spring.annotation.main.MainClass.main(MainClass.java:57)