AOP是Spring中的一种动态技术,支持对类的方法的增强,在对象创建的过程中会判断该bean是否需要增强,该bean的class中是否有方法在切入点上,如果在切入点上会创建相应的切面,有切面的bean就会相应的去创建代理对象。
Spring生态技术中AOP的应用有很多,比如事务,通过增强方法拦截异常进行回滚等。
AOP是增强方法,在不修改源代码情况下,进行对方法功能等扩展,其场景有很多,比如,缓存,增强某个方法使得根据方法的参数进行缓存的维护,有缓存的走缓存返回无缓存的走原始方法内容获取。再比如,监控,监控某个方法的调用信息,成功或失败,将信息发送给统计端做实时QPS、tps、tp99等指标的统计,以及方法可用率的计算等。
老弟在平时的工作中AOP相关的内容使用的很有限,京东的基础设置比较全,如上述的监控,在监控组件的客户端都有提供相关的注解支持。
老弟就搞了一下缓存的注解增强的实现,截止目前,老弟开发了基于注解的缓存配置方案,该方案目前只适用于接口无参的方法,关于动态的key的注解配置目前还没想好怎么做。还有是基于注解实时设置Log4J2的自定义参数ID,简单来讲就是提取方法参数中的requestId,设置日志容器的参数,使得我们通过日志搜索引擎基于ID,快速搜索到单次请求的全链路的内容。
AOP的包是spring-aop,我们去IED项目下的External Libraries中找到 spring-aop 的jar,在META-INF目录中找到 spring.handlers 文件,文件中配置的是如下的内容。
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
故知,aop相关的自定义的内容是在AopNamespaceHandler中配置的,当然这是aop传统的自定义标签的解析的内容是在这里处理的(就不仔细过其中内容了,主要看注解的启动方式)。当下,aop开启的方式是基于注解,@EnableAspectJAutoProxy(proxyTargetClass = false,exposeProxy = true)
注解的内容:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*
* true
* 1、目标对象实现了接口 - 使用CGLIB代理机制
* 2、目标对象没有实现接口(只有实现类) - 使用CGLIB代理机制
*
* false
* 1、目标对象实现了接口 - 使用JDK动态代理机制(代理所有实现了的接口)
* 2、目标对象没有接口(只有实现类) - 使用CGLIB代理机制
*
* 都是动态代理就是实现的方式不一样而已。
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
查看上述代码可知,EnableAspectJAutoProxy导入了@Import(AspectJAutoProxyRegistrar.class)类。
AspectJAutoProxyRegistrar类
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/**
* AUTO_PROXY_CREATOR_BEAN_NAME 这个就是AOP入口类的 名称。
* 有时可能会有覆盖性操作,名称需要记住。
*/
/**
* 注册AOP入口类
*/
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
/**
* 与xml不同的是基于注解方式需要获取注解的属性配置,并设置进入beanDefinition中
*
* true
* 1、目标对象实现了接口 - 使用CGLIB代理机制
* 2、目标对象没有实现接口(只有实现类) - 使用CGLIB代理机制
*
* false
* 1、目标对象实现了接口 - 使用JDK动态代理机制(代理所有实现了的接口)
* 2、目标对象没有接口(只有实现类) - 使用CGLIB代理机制
*/
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
上述注册类中实现了ImportBeanDefinitionRegistrar,在refresh中的invokeBeanFactoryPostProcessors(beanFactory);会执行到ConfigurationClassPostProcessor的内容,会具体执行:@import @importResource @Bean的逻辑,最终会执行到之前@Import中的AspectJAutoProxyRegistrar.class的registerBeanDefinitions这个方法。
该方法的内容:
在DI依赖注入后,需要进行bean实例化的后置处理,有一些初始化方法,在最后还会进行AOP的判断。
AbstractAutowireCapableBeanFactory -> initializeBean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// ... ... 省略Aware接口调用,@postConstruct,initializeBean接口调用,init-method方法调用省略
/**
* Aop入口,有切面的实例才会被代理。
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
AbstractAutowireCapableBeanFactory -> applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
/**
* AOP的入口是一个BeanPostProcessor的应用,是抽象类AbstractAutoProxyCreator
*
* 抽象类AbstractAutoProxyCreator的子类是何时注入进来的?
* 解析自定义xml 或 注解扫描过程中某个Bean的信息有 @EnableAspectJAutoProxy
* Spring保存的是代理对象还是被代理对象?
* 被代理的对象
*/
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
关键判断Bean是否有切面是否创建代理对象的方法。
AbstractAutoProxyCreator -> postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
/**
* 关键方法 主要是看bean是否有切面。有切面就给这个bean创建代理对象
*/
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
AbstractAutoProxyCreator -> wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// ... ... 省略
/**
* 如果当前bean需要被代理就会返回一个不为空的切面数组( Object[])。
* 主要是找bean相关的advisor切面数组。
* 重要程度:* * * * *
*/
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
/**
* 如果有切面则生成该Bean的代理
*/
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
/**
* 把被代理对象bean实例封装到SingletonTargetSource对象中
* TargetSource 这种接口的实现类 封装的是被代理的对象
* 创建代理对象
*/
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
上述方法主要内容是,先调用getAdvicesAndAdvisorsForBean判断当前bean是否有切面数组,如果有切面数组则需要进行代理。代理调用的方法式createProxy方法,会根据不同的情况使用不同的动态代理技术。
AbstractAdvisorAutoProxyCreator -> getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(
Class> beanClass, String beanName, @Nullable TargetSource targetSource) {
/**
* 找到合格的切面,重点看
* 搜集@Aspectj的所有类
*/
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
继续调用findEligibleAdvisors方法寻找切面。
AbstractAdvisorAutoProxyCreator -> findEligibleAdvisors
protected List findEligibleAdvisors(Class> beanClass, String beanName) {
// 找到候选的切面过程,其实就是找有@Aspectj注解的过程,把工程中所有有注解的类封装到Advisor返回。
// 为什么是候选?需要代理的类是beanClass,findCandidateAdvisors是找到所有的切面。
// 重点
List candidateAdvisors = findCandidateAdvisors();
// 判断后选切面是否作用在当前beanClass上面,就是一个匹配的过程,过滤掉不需要拦截beanClass类的切面。
// 简单理解就是判断这个类是否在那个pointcut表达式里面
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对有@Order @Priority进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
// 类在表达式里面就说明这个类绝对会生成代理
return eligibleAdvisors;
}
上述方法重点是调用 findCandidateAdvisors 方法获取工程中所有有@Aspectj注解的类封装到Advisor中返回,Advisor代指切面。
AnnotationAwareAspectJAutoProxyCreator -> findCandidateAdvisors
@Override
protected List findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
/**
* 创建候选的切面 buildAspectJAdvisors
*/
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
主要看创建候选切面的内容,this.aspectJAdvisorsBuilder.buildAspectJAdvisors 方法的调用。
BeanFactoryAspectJAdvisorsBuilder -> buildAspectJAdvisors
public List buildAspectJAdvisors() {
// ... ...
/**
* 拿到beanFactory中所有beanDefinition的名称
*/
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// ... ...
// 判断类上是否有@Aspectj注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 创建获取有@Aspectj注解类的工厂实例,负责获取所有@Aspectj注解类的实例
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
/**
* 创建切面advisor实例
*/
List classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
// ... ...
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// ... ...
return advisors;
}
上述方法主要内容是遍历 BeanDefinition,判断类上是否有@AspectJ注解,建获取有@Aspectj注解类的工厂实例,负责获取所有@Aspectj注解类的实例。
调用 getAdvisors 方法,创建切面信息。
ReflectiveAspectJAdvisorFactory -> getAdvisors 创建切面数组
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 从工厂中获取有@Aspectj注解的class
Class> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 从工厂中获取有@Aspectj注解的类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// 创建工厂的装饰类,获取实例只会获取一次
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
/**
* 循环没有@PointCut注解的方法,pointCut是一个切点并非是一个增强方法。
*
* @PointCut 里面只有一个表达式,并非是增强的内容
*/
List advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
/**
* 这里比较重要,创建advisor。
*/
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// ... ...
// 判断属性上是否有引介注解
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
// 判断属性上是否有DeclareParennts注解,如果有返回切面
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
该方法首先是从工厂中获取有@AspectJ注解的Class,获取有@Aspectj注解的类的名称,循环没有@PointCut注解的方法(实际功能方法并非是切入点),调用getAdvisor方法创建切面。不断的加入到advisors这个列表中。
ReflectiveAspectJAdvisorFactory -> getAdvisor 创建切面
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获取pointCut对象,主要是从注解中提取表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建Advisor切面类,这才是真正的切面类,一个切面类中肯定要有 pointCut 和 advice
// 这里pointCut是expressionPointcut,advice增强方法是candidateAdviceMethod
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
上述getAdvisor中,获取pointCut对象,主要是从注解中提取表达式。 创建Advisor切面类,这才是真正的切面类,一个切面类中肯定要有 pointCut 和 advice,这里pointCut是expressionPointcut,advice增强方法是candidateAdviceMethod。其实最终创建出来的数组就是增强方法的数组 Interceptors,就是下述方法 getAdvice 创建的东西。。
Advice 增强内容的创建
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 获取有@Aspectj注解的类
Class> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 找到candidateAdviceMethod方法上面的注解,并且包装成AspectJAnnotation对象,这个对象中就有注解类型
AspectJAnnotation> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// ... ...
AbstractAspectJAdvice springAdvice;
// advice创建,增强创建
// 根据不同的注解类型来创建不同的advice
// 代理类调用方法时所有的advice对象会包装成MethodInterceptor对象。前置增强和拿到返回值后置通知没实现MethodInterceptor接口
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
// 实现了MethodInterceptor接口
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
// 实现了MethodBeforeAdvice接口
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
// 实现了MethodInterceptor接口
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
// 实现了AfterReturningAdvice接口,没有实现MethodInterceptor接口
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
// 实现了MethodInterceptor接口
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// ... ...
return springAdvice;
}
基于切入点和advie创建实际的advice,获取有@Aspectj注解的类,找到candidateAdviceMethod方法上面的注解,并且包装成AspectJAnnotation对象,这个对象中就有注解类型,根据不同的注解类型来创建不同的advice。 代理类调用方法时所有的advice对象会包装成MethodInterceptor对象。前置增强和拿到返回值后置通知没实现MethodInterceptor接口
AbstractAutoProxyCreator -> createProxy
protected Object createProxy(Class> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// ......
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// ......
// 把advice类型的增强 包装成advisor切面。
// 本身已经是advisor,为什么还要包装一下advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 用来控制代理工程被配置后是否还允许修改代理的配置,默认为false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 获取代理的实例
return proxyFactory.getProxy(getProxyClassLoader());
}
这里会把传进来的specificInterceptors,调用 buildAdvisors 方法统一整理,对自定义的advice要进行包装,把advice包装成advisor对象,切面对象。
getProxy方法首先要判断使用哪种动态代理的技术.
DefaultAopProxyFactory -> createAopProxy
public 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);
}
}
JDK Proxy
JdkDynamicAopProxy -> getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
/**
* jdk的动态代理
*/
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 拿到接口 proxiedInterfaces,h:this是InvocationHandler接口的实现类的实例
// 当前的类JdkDynamicAopProxy实现了InvocationHandler,当前类有invoke方法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy实现了InvocationHandler接口,同样他就有invoke方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* invoke方法
*/
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// 从代理工厂拿到TargetSource对象,该对象包装了被代理实例bean
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 被代理对象的equals方法和hashcode方法是不能被代理的,不会走切面
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// ... ...
Object retVal;
// exposeProxy 属性 是否暴露代理对象
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
// 代理对象,会放入threadLocal ,
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// target 就是一个被代理的实例
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// 从代理工厂中拿过滤器链条 Object是一个MethodInterceptor类型的对象,其实就是一个advice对象
List
关键的点就是:
AOP的内容就是增强我们的方法,在增强方法的设计上是采用动态代理的模式进行动态调用的。JDK 动态代理的链式调用,可以理解为我把这个bean的增强的方法串在一起,前置增强,环绕增强,后置增强等链式调用。