Spring AOP实现原理

来源:互联网 发布:杭州宇石网络 编辑:程序博客网 时间:2024/06/05 03:07

在Spring AOP框架中学习了动态AOP的几种实现方式,本篇重点来学习一下动态AOP的实现原理。

Spring AOP是利用代理模式,在运行时生成一个目标对象的代理,并且使用代理代替目标对象,整个过程对使用者透明,使用者无法像使用目标对象一样使用代理对象,代理对象类型是目标对象所属类的子类或者接口实现,这个子类也是在运行时动态生成,这个生成子类的过程使用操作字节码技术,Spring框架中使用两种字节码技术:JDK动态代理和CGLIB,当目标类实现了接口时使用JDK动态代理,否则使用CGLIB代理。

AOP的实现包含下面几个步骤:

  • 根据配置或注解解析切面。
  • 生成AOP代理对象,给目标对象生成一个代理类以及代理类实例,根据解析出的切面,生成通知链设置到代理对象,在代理的回调中会执行通知链。
  • 把AOP代理对象注册到容器中代替目标对象,当使用者向容器请求目标bean时,容器会返回代理对象。

下面对这几个步骤逐一的分析。

切面解析

在分析切面解析过程之前,首先先了解一下几个关键的接口,看下面的类图。

AOP类图

  • PointCut:描述切点,在进行切点匹配时,使用ClassFilter进行类匹配,MethodMatcher进行执行方法匹配。
  • Advice:通知,AfterAdvice后通知,BeforeAdvice前通知,DynamicIntroductionAdvice引用通知,环绕通知通过Interceptor实现。
  • Advisor:通知器,也就是切面,PointcutAdvisor切点通知器,IntroductionAdvisor引用通知器。

在创建AOP代理之前需要把相关的切面配置解析成上面类图中的接口子类的对象,对于ProxyFactoryBean来说,没有这个过程,因为这种方式下不能使用切点。

切面解析完成之后,把解析出的通知添加通知链中,AOP代理对象引用该通知链执行切面通知逻辑。对于aop标签方式和注解方式添加通知链这个动作的代码是类似的,解析切面这个过程有些差异,下面分析一下这两种方式下的切面解析。

aop标签解析

在Spring bean定义解析源码分析中提到了,Spring的扩展名称空间都需要定义个名称空间解析器,这个解析在META-INF/spring.handlers文件中注册,通过查看spring-aop-3.2.9.RELEASE.jar包的META-INF/spring.handlers文件可以看到aop名称空间的解析器是AopNamespaceHandler。

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
再AopNamespaceHandler中可以看到aop下各个标签对应的解析器。

public class AopNamespaceHandler extends NamespaceHandlerSupport {/** * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}' * and '{@code scoped-proxy}' tags. */public void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}}
在init方法中注册了各个标签的解析器,可以看到aop:config标签的解析器是ConfigBeanDefinitionParser。
在ConfigBeanDefinitionParser的parse方法中对aop:config下面的三个直接子标签pointcut、advisor、aspect分别进行解析。

List<Element> childElts = DomUtils.getChildElements(element);for (Element elt: childElts) {String localName = parserContext.getDelegate().getLocalName(elt);if (POINTCUT.equals(localName)) {parsePointcut(elt, parserContext);}else if (ADVISOR.equals(localName)) {parseAdvisor(elt, parserContext);}else if (ASPECT.equals(localName)) {parseAspect(elt, parserContext);}}

pointcut标签解析

解析器会为pointcut标签创建一个切点bean定义,并且把bean定义注册到容器中,代码在ConfigBeanDefinitionParser类的parsePointcut和createPointcutDefinition方法。

private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {String id = pointcutElement.getAttribute(ID);String expression = pointcutElement.getAttribute(EXPRESSION);AbstractBeanDefinition pointcutDefinition = null;try {this.parseState.push(new PointcutEntry(id));pointcutDefinition = createPointcutDefinition(expression);pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));String pointcutBeanName = id;if (StringUtils.hasText(pointcutBeanName)) {parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);}else {pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);}parserContext.registerComponent(new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));}finally {this.parseState.pop();}return pointcutDefinition;}protected AbstractBeanDefinition createPointcutDefinition(String expression) {RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);beanDefinition.setSynthetic(true);beanDefinition.getPropertyValues().add(EXPRESSION, expression);return beanDefinition;}

该切点bean定义的类型是AspectJExpressionPointcut,这个类同时实现了ClassFilter和MethodMatcher接口执行类匹配和方法匹配逻辑。它有一个expression属性设置表达式,AspectJ最终会把该表达式解析成一个PointcutExpression对象执行相关的语义,表达式的解析过程比较复杂,在这不讨论。

aspect标签解析

aspect标签的解析要相对复杂一些,扫描它下面的所有通知子标签(aop:before、aop:after等标签)。

1、把这些标签都解析成通知类,通知标签的方法属性(method属性)会被解析成一个MethodLocatingFactoryBean类型的bean,把aspect引用的bean名称(aop:aspect标签的ref属性)和method方法通过属性注入到MethodLocatingFactoryBean类型bean中。

2、生成一个SimpleBeanFactoryAwareAspectInstanceFactory类型的bean,这个bean的作用是用来加载aspect引用的bean,把aspect引用的bean名称通过属性注入到该这个bean中。

3、生成一个通知(Advice)bean。

3.1、把aspect bean id和order(指定通知在通知链中的顺序)通过属性注入到该bean。

3.2、把各个通知标签特有属性注入(比如returning,throwing等属性)。

3.3、把上面生成方法MethodLocatingFactoryBean类型bean通过构造器注入。

3.4、构造子注入引用的切点bean,pointcut或pointcut-ref指定,如果是pointcut-ref属性,直接引用这个bean,如果是pointcut属性,生成一个匿名的切点bean。

3.5、构造子注入上面的SimpleBeanFactoryAwareAspectInstanceFactory类型bean。

通知bean的类型根据标签的不同而不同,aop;before对应AspectJMethodBeforeAdvice,aop:after对应AspectJAfterAdvice,aop:aroude对应AspectJAroundAdvice,在通知方法中通过反射调用method属性中设置的方法。通过ConfigBeanDefinitionParser类的getAdviceClass方法可以看出标签和类的对应关系。

private Class getAdviceClass(Element adviceElement, ParserContext parserContext) {String elementName = parserContext.getDelegate().getLocalName(adviceElement);if (BEFORE.equals(elementName)) {return AspectJMethodBeforeAdvice.class;}else if (AFTER.equals(elementName)) {return AspectJAfterAdvice.class;}else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {return AspectJAfterReturningAdvice.class;}else if (AFTER_THROWING_ELEMENT.equals(elementName)) {return AspectJAfterThrowingAdvice.class;}else if (AROUND.equals(elementName)) {return AspectJAroundAdvice.class;}else {throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");}}

4、生成通知器bean,这个bean的类型是AspectJPointcutAdvisor,通过构造子把上面创建的通知bean注入,属性注入order属性,并且把这个通知器bean匿名注入到容器中。

5、此外如果切面内部定义了切点和引用,会进行切点和引用bean解析,切点bean解析和上面的切点解释是一样的,关于引用解析会生成一个DeclareParentsAdvisor类型的bean。

advisor标签解析

advisor标签会被解析成一个DefaultBeanFactoryPointcutAdvisor类型的bean并且注入到容器中,如果指定了id属性通过id注册,如果没有指定匿名注册。属性注入advisor引用的bean,如果定义内部pointcut,解析pointcut,解析过程和上面的切点解析过程一致。aop:advisor标签的解析相对比较简单,代码在ConfigBeanDefinitionParser类的parseAdvisor和createAdvisorBeanDefinition方法。

private void parseAdvisor(Element advisorElement, ParserContext parserContext) {AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);String id = advisorElement.getAttribute(ID);try {this.parseState.push(new AdvisorEntry(id));String advisorBeanName = id;if (StringUtils.hasText(advisorBeanName)) {parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);}else {advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);}Object pointcut = parsePointcutProperty(advisorElement, parserContext);if (pointcut instanceof BeanDefinition) {advisorDef.getPropertyValues().add(POINTCUT, pointcut);parserContext.registerComponent(new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));}else if (pointcut instanceof String) {advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));parserContext.registerComponent(new AdvisorComponentDefinition(advisorBeanName, advisorDef));}}finally {this.parseState.pop();}}private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);advisorDefinition.setSource(parserContext.extractSource(advisorElement));String adviceRef = advisorElement.getAttribute(ADVICE_REF);if (!StringUtils.hasText(adviceRef)) {parserContext.getReaderContext().error("'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());}else {advisorDefinition.getPropertyValues().add(ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));}if (advisorElement.hasAttribute(ORDER_PROPERTY)) {advisorDefinition.getPropertyValues().add(ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));}return advisorDefinition;}


上面说的生成bean和注入bean到容器,只会生成和注册bean定义即BeanDefinition,此时不会被进行bean的实例化初始化,bean的实例化操作会在调用容器的getBeanXXX方法中执行。上面的过程的代码实现可以查看ConfigBeanDefinitionParser类的parseAspect、parseAdvice、createAdviceDefinition这几个方法。上面说的生成bean和注入bean到容器,只会生成和注册bean定义即BeanDefinition,此时不会被进行bean的实例化初始化,bean的实例化操作会在调用容器的getBeanXXX方法中执行。上面的过程的代码实现可以查看ConfigBeanDefinitionParser类的parseAspect、parseAdvice、createAdviceDefinition这几个方法。
因为bean定义文件的解析时在容器初始化的,所以aop标签的解析也是在容器初始化时执行的。

aspect注解

在Spring AOP框架列举注解的使用方式,要使用aop注解,需要在bean定义文件中添加<aop:aspectj-autoproxy />,从这个标签开始分析aspect注解的解析过程,在上面列出
AopNamespaceHandler代码可以看到aspectj-autoproxy的标签解析器是AspectJAutoProxyBeanDefinitionParser这个类,这个解析器在解析标签时给容器注入了一个AnnotationAwareAspectJAutoProxyCreator类型的bean,bean的id是org.springframework.aop.config.internalAutoProxyCreator,从这个类的parse方法的代码可以看出来。

public BeanDefinition parse(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);extendBeanDefinition(element, parserContext);return null;}private void extendBeanDefinition(Element element, ParserContext parserContext) {BeanDefinition beanDef =parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);if (element.hasChildNodes()) {addIncludePatterns(element, parserContext, beanDef);}}
在AnnotationAwareAspectJAutoProxyCreator类中有一个重要的属性aspectJAdvisorsBuilder,它的类型是BeanFactoryAspectJAdvisorsBuilder,这个类就是用来解析切面相关的注解,与aop标签解析不同的是,这个解析过程会生成一个个具体的切面相关的对象实例,而不仅仅是bean定义。
BeanFactoryAspectJAdvisorsBuilder会对容器中所有的bean进行扫描,过滤出所属类型添加了@Aspect注解的bean,过滤出类中所有添加了通知注解的方法,并把它们解析成相关的通知器,详细的解析过程在本篇不深入,如果感兴趣可以从BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors一步一步跟踪。

public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = null;synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List<Advisor> advisors = new LinkedList<Advisor>();aspectNames = new LinkedList<String>();String[] beanNames =BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {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 weavedClass beanType = this.beanFactory.getType(beanName);if (beanType == null) {continue;}if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}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;}}if (aspectNames.isEmpty()) {return Collections.EMPTY_LIST;}List<Advisor> advisors = new LinkedList<Advisor>();for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors;}
那么在什么时机触发@Aspect注解解析?查看一下BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法的调用树。

调用树
AnnotationAwareAspectJAutoProxyCreator类是AbstractAutoProxyCreator的子类,并且它还实现了InstantiationAwareBeanPostProcessor,所以@Aspect注解的解析动作是在这个postProcessBeforeInstantiation方法发起的,关于这个方法在后面还会提到。

创建AOP代理实例

AOP代理实例通过代理工厂ProxyFactory来创建,在创建代理之前首要要调用AbstractAutoProxyCreator类的getAdvicesAndAdvisorsForBean方法整合目标对象的通知链,如果是注解实现形式,在这个过程中会触发注解的解析,如果是标签实现方式那么直接向容器请求Advisor类型的bean,这些bean在容器启动时就已经被解析并且注册。

获取到所有通知链之后,根据切面的切点表达式过滤出目标对象符合的通知器,下面两个条件至少满足一个:

  • 调用ClassFilter判断目标对象的类是否满足条件
  • 遍历目标对象所属类的所有共有方法,检查这些方法是否至少有一个满足条件

过滤之后对这些通知器根据order排序,代码在AbstractAdvisorAutoProxyCreator类的findEligibleAdvisors方法。

protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {List<Advisor> candidateAdvisors = findCandidateAdvisors();List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}
把上面过滤出来的通知器添加到代理工厂ProxyFactory中,创建代理。

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory();// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.proxyFactory.copyFrom(this);if (!shouldProxyTargetClass(beanClass, beanName)) {// Must allow for introductions; can't just set interfaces to// the target's interfaces only.Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);for (Class<?> targetInterface : targetInterfaces) {proxyFactory.addInterface(targetInterface);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}return proxyFactory.getProxy(this.proxyClassLoader);}
上面有个buildAdvisors方法的作用对传入的拦截器参数做适配,因为拦截有可能是Advice和Advisor类型,这里统一把它们都适配成Advisor类型。

创建一个AopProxy实例来创建代理,根据目标类是否实现了接口来决定是使用Jdk动态代理还是CGLIB代理,看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()) {return new JdkDynamicAopProxy(config);}return CglibProxyFactory.createCglibProxy(config);}else {return new JdkDynamicAopProxy(config);}}
关于动态代理和CGLIB代理,对于使用者来讲主要区别是回调方式不一样,JDK动态代理的回调时InvocationHandler,而CGLIB是CallBack,对于这两种代理的使用方式这里不详细介绍,感兴趣的可以参考相关文档。

切面逻辑在代理的回调中执行,来看一下代理的回调方法,无论是动态代理还是CGLIB代理,回调方法调用的主逻辑是一样的,所以这里只看一下JDK动态代理的回调就可以了,看一下JdkDynamicAopProxy类的invoke方法,当拦截到目标对象方法调用时会进入这个方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {...List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.if (chain.isEmpty()) {// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);}else {// We need to create a method invocation...invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}    ...}

JdkDynamicAopProxy中一个advised属性,这个属性就是上面的代理工厂ProxyFactory,通过advised的getInterceptorsAndDynamicInterceptionAdvice方法获取拦截链,通过前面的分析可以知道目标对象符合条件的通知器都已经添加到代理工厂中了,这个过程主要是对代理工厂中通知器进行适当的封装,如果是切点通知器(PointcutAdvisor),把方法拦截器MethodInterceptor和MethodMatcher封装到InterceptorAndDynamicMethodMatcher中返回,如果是其它的通知器直接返回Interceptor列表,并且把通知器Advisor适配成拦截器Interceptor,通过通知器适配器AdvisorAdapter来完成,比如前通知器的通知适配器是MethodBeforeAdviceAdapter。

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {public boolean supportsAdvice(Advice advice) {return (advice instanceof MethodBeforeAdvice);}public MethodInterceptor getInterceptor(Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();return new MethodBeforeAdviceInterceptor(advice);}}
通过这个类的代码可以看到,返回的拦截器封装了前通知MethodBeforeAdvice,激活MethodBeforeAdviceInterceptor这个拦截器时会调用前通知器的before方法。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice;/** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );return mi.proceed();}}

回到代理的回调中,如果目标对象没有任何拦截器,则通过反射直接调用目标对象的目标方法,如果存在拦截器,则把拦截器设置到ReflectiveMethodInvocation对象中,触发该对象的proceed方法,看一下这个proceed方法的代码。

public Object proceed() throws Throwable {//We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
在proceed方法中,遍历拦截器,并且通过方法匹配器(如果存在)进行方法和参数匹配,如果不匹配,处理下一个拦截器,如果匹配,触发拦截器即interceptor.invoke方法,从前面的分析可以看到这个invoke方法会调用通知逻辑即前通知的before或后通知的after方法。从代码中也可以看出,当拦截器被触发之后,该拦截器可以选择决定是否继续后面的拦截器处理。用AspectJAfterAdvice通知的代码举个例子。

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {super(aspectJBeforeAdviceMethod, pointcut, aif);}public Object invoke(MethodInvocation mi) throws Throwable {try {return mi.proceed();}finally {invokeAdviceMethod(getJoinPointMatch(), null, null);}}public boolean isBeforeAdvice() {return false;}public boolean isAfterAdvice() {return true;}}
我们看到在AspectJAfterAdvice的invoke方法中调用mi.proceed方法继续了后面的处理,这个mi就是上面的ReflectiveMethodInvocation对象,如果想终止后面的拦截器处理,只要在invoke方法中不调用mi.proceed就可以了。

通过上面的代码分析,我们可以看出在代理对象的回调中,会逐步的触发符合要求的拦截器,在我们例子里面最终会调用到LogAspect、LogAdvisor中的相关代码。

替换目标bean

通过上面的分析,了解了代理对象创建的代码以及代理对象如何激活切面逻辑,但是这些AOP代理对象在何时创建?如何把它们作为目标bean的替代品注册到容器中,通过上面的代码看到,代理对象的创建是在AbstractAutoProxyCreator类的postProcessBeforeInstantiation方法中触发的,这个类实现InstantiationAwareBeanPostProcessor接口。通过Spring IOC容器bean初始化源码分析中的分析,任何bean在实例化之前都会遍历容器中所有的InstantiationAwareBeanPostProcessor类型bean并且调用它的postProcessBeforeInstantiation方法,如果这个方法返回了一个非空的实例,那么会使用这个bean来代理目标bean,容器就是这个地方偷偷把目标bean给替换了。可以参考AbstractAutowireCapableBeanFactory类中的代码。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {      Object bean = null;      if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {          // Make sure bean class is actually resolved at this point.          if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {              bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);              if (bean != null) {                  bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);              }          }          mbd.beforeInstantiationResolved = (bean != null);      }      return bean;  }    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)          throws BeansException {        for (BeanPostProcessor bp : getBeanPostProcessors()) {          if (bp instanceof InstantiationAwareBeanPostProcessor) {              InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;              Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);              if (result != null) {                  return result;              }          }      }      return null;  }    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)          throws BeansException {        Object result = existingBean;      for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {          result = beanProcessor.postProcessAfterInitialization(result, beanName);          if (result == null) {              return result;          }      }      return result;  }  
对于@Apsect注解,在面介绍了,会自动生成一个AnnotationAwareAspectJAutoProxyCreator类型的bean,这个bean正是AbstractAutoProxyCreator类的子类,所有在容器bean实例化之前会触发它的postProcessBeforeInstantiation方法,执行切面解析和AOP代理创建逻辑。

对于aop标签,在上面的分析过程中,在ConfigBeanDefinitionParser解析器中还有个关键的步骤没有提到,这个解析器在解析时会自动给容器注册一个AspectJAwareAdvisorAutoProxyCreator类型的bean。

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);}
AspectJAwareAdvisorAutoProxyCreator是AnnotationAwareAspectJAutoProxyCreator的父类,也是AbstractAutoProxyCreator的子类,所以标签式实现是通过它来触发AOP代理创建逻辑并且用代理替换目标对象,如果同时使用了aop标签和@Aspect注解,那么容器只会生成一个AnnotationAwareAspectJAutoProxyCreator类型bean,因为它继承了AspectJAwareAdvisorAutoProxyCreator,所以涵盖了标签式通知链生成逻辑。

对于ProxyFactoryBean,直接在它的getObject方法中触发代理创建,ProxyFactoryBean不涉及切入点,相比标签式和注解式的是实现方式它要简单很多,整个代理的创建过程和另外两种也基本上类似,所以上面只着重分析了标签式和注解式的实现原理,对ProxyFactoryBean分析略过。

原创粉丝点击