面向切面编程(Aspect Oriented Programming,AOP)是什么?
AOP为什么出现?
- 提高代码重用性;
- 概念分离:分离功能性需求和非功能性需求。将功能性需求从非功能性需求中分离出来。
应用场景
- 权限控制
- 缓存控制
- 事务控制
- 审计日志
- 性能监控
- 分布式追踪
- 异常处理
Spring AOP的通过代理实现
通过DefaultAopProxyFactory.java源码可以看到AOP由jdk和cglib两种方式实现。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
Spring AOP的使用
在Spring中主要使用注解@Aspect、@Pointcut、@Before、@After、@AfterReturning、@AfterThrowing以及@Around进行面向切面编程。
1 | @Retention(RetentionPolicy.RUNTIME) |
如上代码是@Aspect注解的定义,ElementType.TYPE可以看出该注解作用目标是接口、类、枚举、注解,@Aspect注解,Spring通过@Aspect注解切面并把它应用到目标对象上。
1 | @Retention(RetentionPolicy.RUNTIME) |
如上代码是@Pointcut注解的定义,value()用来定义切面所在的位置,定义方式有以下几种方式:1
2
3
4
5
6
7
8
9// execution定义切面,匹配符合表达式的所有方法
@Pointcut("execution(* com.xjtu.springbootstudy.aop.bymyself.service.ProgrammerService.work())")
// within用于匹配类,对应类下的所有方法都执行切面方法;
@Pointcut("within(com.xjtu.springbootstudy.aop.bymyself.service.*)")
// @annotation用于匹配自定义注解,如下面的@SignLog注解,再将@SignLog放在想定义切面的方法
@Pointcut("@annotation(com.xjtu.springbootstudy.aop.bymyself.annotation.SignLog)")
// @within用于匹配自定义注解,如下面的@SignLog注解,再将@SignLog放在想定义切面的类上
@Pointcut("@within(com.xjtu.springbootstudy.aop.bymyself.annotation.SignLog))")
public void log(){ }
如上对log()添加注解,@Pointcut注解中value定义切面位置,使用execution、within、@annotation、@within等方式设置切面。
- @before在目标方法开始执行时执行;
- @after在目标方法执行结束前执行;
- @AfterReturning在目标方法执行正确返回前执行;
- @AfterThrowing在目标方法执行异常时执行,
- @Around环绕执行,一般是前4个无法实现期望功能时,才使用这个注解。
我写了一个简单示意切面程序,如下所示,对应执行结果也展示下下方。有个疑问就是@after和@AfterReturning注解的方法谁先执行?根据执行结果也可以看出
@after注解的方法先执行,@AfterReturning注解的方法后执行。
1 | @Before(value = "log()") |