转载

Spring源码解析 -- AOP原理(1)

源码分析基于spring 4.3.x

本文通过阅读Spring源码,分析Spring AOP的功能是如何实现的。

关于阅读源码的思路,可参考 -- 如何阅读java源码

首先,明确几个概念

pointcut:切入点,根据方法名或者正则表达式去拦截一个方法。

advice:通知,在拦截到方法执行前或执行后的增强操作。

aspect:切面,一个切面可以包括多个切入点和通知,spring内部的切入点和通知是无序的。

advisor:只有一个通知和一个切入点的单元切面,可以看做一种特殊的aspect。

开始阅读源码前,本文主要关注的几个问题:

<aop:aspectj-autoproxy/> 

<aop:aspectj-autoproxy/> 的作用

aspectj-autoproxy是spring内部定义的标签。

前面解析Spring读取bean元数据的文章说过,在spring中除了<beans>标签,其他标签需要编写一个NamespaceHandlerSupport实现类来完成标签解析工作。

在spring源码中搜索一下,就可以发现aspectj-autoproxy的解析类AopNamespaceHandler

public void init() { this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); }

而AspectJAutoProxyBeanDefinitionParser类负责对aspectj-autoproxy标签进行解析:

AspectJAutoProxyBeanDefinitionParser#parse

public BeanDefinition parse(Element element, ParserContext parserContext) { AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); extendBeanDefinition(element, parserContext); return null; }

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary -> AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }

这里将AnnotationAwareAspectJAutoProxyCreator注入到spring上下文环境中。

AnnotationAwareAspectJAutoProxyCreator是一个关键的类,继承了BeanPostProcessor接口,它负责完成创建切面工作。

创建advisor

AbstractAutoProxyCreator#postProcessAfterInitialization -> AbstractAutoProxyCreator#wrapIfNecessary

(AbstractAutoProxyCreator是AnnotationAwareAspectJAutoProxyCreator的父类)

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { ... Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // #1 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // #2 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

#1 根据bean元数据构造通知和单元切面

#2 创建代理对象

getAdvicesAndAdvisorsForBean -> AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean -> AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); // #1 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // #2 extendAdvisors(eligibleAdvisors); // #3 if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); // #4 } return eligibleAdvisors; }

这是一个非常重要的方法,实现了几个关键步骤

#1 findCandidateAdvisors -- 查找所有的单元切面(第一次会创建)

#2 findAdvisorsThatCanApply -- 根据目标bean的class过滤一部分的单元切面

#3 extendAdvisors -- 扩充单元切面列表,spring会根据需要添加一些内部使用的单元切面

#4 sortAdvisors -- 对单元切面排序

查找所有的单元切面

findCandidateAdvisors -> AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors -> BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { // #1 List<Advisor> advisors = new LinkedList<Advisor>(); aspectNames = new LinkedList<String>(); String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { // #2 if (!isEligibleBean(beanName)) { // #3 continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } if (this.advisorFactory.isAspect(beanType)) { // #4 aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); // #5 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // #6 if (this.beanFactory.isSingleton(beanName)) { // #7 this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); // #8 } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } ... #9 }

#1 典型的double check

#2 遍历所有的bean

#3 判断是否为合格的切面类

#4 是否为切面类(是否有Aspect注解)

#5 获取切面信息

#6 构建一系列的单元切面

#7 加入缓存

#8 加入结果

#9 缓存不为空,从缓存中获取数据返回

步骤 #6 调用ReflectiveAspectJAdvisorFactory.getAdvisors

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass); MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); // #1 List<Advisor> advisors = new LinkedList<Advisor>(); for (Method method : getAdvisorMethods(aspectClass)) { // #2 Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); // #3 if (advisor != null) { advisors.add(advisor); } } ... return advisors; }

#1 lazySingletonAspectInstanceFactory对getAspectInstance进行了缓存,保证getAspectInstance方法返回单例

#2 getAdvisorMethods获取所有没有Pointcut注解的方法(有Pointcut注解的方法不可能是Advisor)

#3 使用方法元数据构造单元切面

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); // #1 if (expressionPointcut == null) { return null; } return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); // #2 }

#1 获取切入点Pointcut,并构建了AspectJExpressionPointcut

#2 创建单元切面InstantiationModelAwarePointcutAdvisorImpl,该类中包含属性 --

被拦截类declaringClass,被拦截方法aspectJAdviceMethod,切入点declaredPointcut和通知instantiatedAdvice。

InstantiationModelAwarePointcutAdvisorImpl#构造方法 -> InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice -> ReflectiveAspectJAdvisorFactory#getAdvice

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { ... // #1 AbstractAspectJAdvice springAdvice; switch (aspectJAnnotation.getAnnotationType()) { // #2 case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } // Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }

#1 aspectInstanceFactory#getAspectMetadata获取切面信息,再获取对应的aspectJAnnotation

#2 根据切面类型,构建不同的通知实现类

@After对应AspectJAfterAdvice

@Around对应AspectJAroundAdvice

@Before对应AspectJMethodBeforeAdvice

@AfterReturning对应AspectJAfterReturningAdvice

@AfterThrowing对应AspectJAfterThrowingAdvice

除了AspectJAroundAdvice,这些通知实现类都实现了MethodInterceptor(方法拦截器接口)。

findAdvisorsThatCanApply 过滤单元切面

这里会遍历所有的单元切面,检查bean的class和class中是否有方法可以匹配对应的单元切面,如果没有则过滤该单元切面。代码比较繁琐,不展开了。

extendAdvisors(eligibleAdvisors)扩充单元切面

AspectJAwareAdvisorAutoProxyCreator.extendAdvisors -> AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary

spring会在advisors列表开始位置添加ExposeInvocationInterceptor。

ExposeInvocationInterceptor是一个特殊的MethodInterceptor,它将当前方法拦截器调用链放置到线程上下文中,以便有需要时使用。

创建代理对象

我们知道,spring通过动态代理类实现aop,有jdk动态代理和cglib两种方法。

如果要使用jdk动态代理,被代理类必须实现一个接口。

这里只关注jdk动态代理如何实现aop。

AbstractAutoProxyCreator#wrapIfNecessary方法 #2 步骤 -> AbstractAutoProxyCreator.createProxy(第三个参数就是Advices)

protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ... Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // #1 for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); // #2 } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); // #3 }

#1 类型检查及转化,如将Advices转换成Advisor

#2 将Advisor添加到proxyFactory中

#3 构造代理对象

proxyFactory.getProxy -> ProxyCreatorSupport.createAopProxy

protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); // #1 }

#1 构造代理对象,createAopProxy方法参数是this,将proxyFactory将自身作为参数,

DefaultAopProxyFactory#createAopProxy

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // #1 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 { // #2 return new JdkDynamicAopProxy(config); } }

#1 根据用户配置和目标bean是否有实现接口,判断是否需要使用ObjenesisCglibAopProxy

#2 使用JDK动态代理

来看看JdkDynamicAopProxy#getProxy

public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); // #1 }

#1 这里构造了jdk的动态代理对象,注意newProxyInstance方法第三个参数是this,即JdkDynamicAopProxy,JdkDynamicAopProxy实现了InvocationHandler。

Spring AOP源码解析内容过长,关于多个通知链式调用的解析留到下一篇文章解析

如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!

Spring源码解析 -- AOP原理(1)

原文  https://segmentfault.com/a/1190000022538024
正文到此结束
Loading...