AOP(Aspect Oriented Programming)是基于切面编程的,可无侵入的在原本功能的切面层添加自定义代码,一般用于日志收集、权限认证等场景。
AOP基本概念
通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理;
Before :前置通知,在连接点方法前调用;对应Spring中@Before注解; After :后置通知,在连接点方法后调用;对应Spring中的@After注解; AfterReturning:返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常;对应Spring中的@AfterReturning注解; AfterThrowing:异常通知,当连接点方法异常时调用;对应Spring中的@AfterThrowing注解; Around:环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法;对应Spring中的@Around注解;
连接点(Join Point): 连接点表示应用执行过程中能够插入切面的一个点。在 Spring AOP 中,连接点总是方法的调用,可以说目标对象中的方法就是一个连接点;
切点(Pointcut): 就是连接点的集合;对应Spring中的@Pointcut注解;
目前Spring支持的切点匹配表达式主要有以下几种: execution:可以定义到的最小粒度是方法,修饰符,包名,类名,方法名,Spring AOP主要也是使用这个匹配表达式; within:只能定义到类;例如@Pointcut(within(com.jnu.example.*)) this:当前生成的代理对象的类型匹配; target:目标对象类型匹配; annotation:针对注解; args:只针对参数; 例如: execution (* com.sample.service..*. *(..)) 整个表达式可以分为五个部分: 1、execution()::表达式主体; 2、第一个*号:表示返回类型, *号表示所有的类型; 3、包名:表示需要拦截的包名,包名后面的..,表明com.sample.service包、及其子包; 4、第二个*号:表示类名,*号表示所有的类; 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个点表示任何参数;
切面(Aspect): 切面是通知和切点的结合;对应Spring中的注解@Aspect修饰的一个类;
目标对象(Target object):即被代理的对象;
代理对象(AOP proxy):包含了目标对象的代码和增强后的代码的那个对象;
自定义注解实例可以参见:注解
@EnableAspectJAutoProxy分析
在spring-boot-autoconfigure-**.jar中,有个配置类,来控制AOP功能的开启和关闭:
@Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) static class AspectJAutoProxyingConfiguration { @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class CglibAutoProxyConfiguration { } } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("org.aspectj.weaver.Advice") @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class ClassProxyingConfiguration { ClassProxyingConfiguration(BeanFactory beanFactory) { if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } } } }