Spring框架系列 - Spring AOP实现原理详解之AOP切面的实现

Posted realpdai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架系列 - Spring AOP实现原理详解之AOP切面的实现相关的知识,希望对你有一定的参考价值。


前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。@pdai


引入


我们应该从哪里开始着手看Spring AOP的源码呢?和我们上文分析的IOC源码实现有什么关系呢?


  1. 前文中我们写了AOP的Demo,根据其XML配置我们不难发现AOP是基于IOC的Bean加载来实现的;这便使我们的主要入口

Spring框架系列(9)

所以理解Spring AOP的初始化必须要先理解​​Spring IOC的初始化​​。

  1. 然后我们就能找到如下初始化的流程和aop对应的handler

即parseCustomElement方法找到parse ​​aop:aspectj-autoproxy​​的handler(org.springframework.aop.config.AopNamespaceHandler)

Spring框架系列(9)

(PS:其实你会发现,最重要的是知识点的关联关系,而不是知识点本身,就后续代码而言不就是打个断点慢慢看的事了么。)

aop配置标签的解析


上文中,我们找到了AopNamespaceHandler,其实就是注册BeanDefinition的解析器BeanDefinitionParser,将​​aop:xxxxxx​​配置标签交给指定的parser来处理。




/**
* Register the @link BeanDefinitionParser BeanDefinitionParsers for the
* @code config, @code spring-configured, @code aspectj-autoproxy
* and @code scoped-proxy tags.
*/
@Override
()
// In 2.0 XSD as well as in 2.5+ XSDs
// 注册解析<aop:config> 配置
registerBeanDefinitionParser("config", ConfigBeanDefinitionParser());
// 注册解析<aop:aspectj-autoproxy> 配置
registerBeanDefinitionParser("aspectj-autoproxy", AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", ScopedProxyBeanDefinitionDecorator());

// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", SpringConfiguredBeanDefinitionParser());


config配置标签的解析

​<aop:config/>​​由ConfigBeanDefinitionParser这个类处理,作为parser类最重要的就是parse方法

@Override
@Nullable
BeanDefinition (Element element, ParserContext parserContext)
CompositeComponentDefinition compositeDef =
CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);

configureAutoProxyCreator(parserContext, element);

List<Element> childElts = DomUtils.getChildElements(element);
(Element elt: childElts)
String localName = parserContext.getDelegate().getLocalName(elt);
(POINTCUT.equals(localName))
parsePointcut(elt, parserContext);

(ADVISOR.equals(localName))
parseAdvisor(elt, parserContext);

(ASPECT.equals(localName))
parseAspect(elt, parserContext);



parserContext.popAndRegisterContainingComponent();
;

打个断点看下

Spring框架系列(9)

parseAspect的方法如下, 处理方法不难,我这里就不展开了

(Element aspectElement, ParserContext parserContext) 
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);


.parseState.push( AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = ArrayList<>();
List<BeanReference> beanReferences = ArrayList<>();

List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
( i = METHOD_INDEX; i < declareParents.size(); i++)
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));


// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
adviceFoundAlready = ;
( i = 0; i < nodeList.getLength(); i++)
Node node = nodeList.item(i);
(isAdviceNode(node, parserContext))
(!adviceFoundAlready)
adviceFoundAlready = ;
(!StringUtils.hasText(aspectName))
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via ref attribute when declaring advices.",
aspectElement, .parseState.snapshot());
;

beanReferences.add( RuntimeBeanReference(aspectName));

AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);



AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);

List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
(Element pointcutElement : pointcuts)
parsePointcut(pointcutElement, parserContext);


parserContext.popAndRegisterContainingComponent();


.parseState.pop();

aspectj-autoproxy配置标签的解析

​<aop:aspectj-autoproxy/>​​则由AspectJAutoProxyBeanDefinitionParser这个类处理的,我们看下parse 方法

@Override
@Nullable
BeanDefinition (Element element, ParserContext parserContext)
// 注册AspectJAnnotationAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 拓展BeanDefinition
extendBeanDefinition(element, parserContext);
;

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法对应如下

(
ParserContext parserContext, Element sourceElement)

BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary对应如下

@Nullable
BeanDefinition (
BeanDefinitionRegistry registry, @Nullable Object source)

registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator., , );

到这里,我们发现AOP的创建工作是交给AnnotationAwareAspectJAutoProxyCreator来完成的。

注解切面代理创建类(AnnotationAwareAspectJAutoProxyCreator)


AnnotationAwareAspectJAutoProxyCreator是如何工作的呢?这时候我们就要看AnnotationAwareAspectJAutoProxyCreator类结构关系了。


如下是类结构关系

Spring框架系列(9)

它实现了两类接口:

  • BeanFactoryAware属于Bean级生命周期接口方法
  • InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”,是容器级生命周期接口方法

结合前文Spring Bean生命周期的流程

Spring框架系列(9)

我们就可以定位到核心的初始化方法肯定在postProcessBeforeInstantiation和postProcessAfterInitialization中。

postProcessBeforeInstantiation

如下是上述类结构中postProcessBeforeInstantiation的方法,读者在自己看代码的时候建议打个断点看,可以方便理解

Spring框架系列(9)

@Override
Object (Class<?> beanClass, String beanName)
Object cacheKey = getCacheKey(beanClass, beanName);

(!StringUtils.hasLength(beanName) || !.targetSourcedBeans.contains(beanName))
// 如果已经在缓存中,则忽略
(.advisedBeans.containsKey(cacheKey))
;

// 是否是aop基础类?是否跳过?
(isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))
.advisedBeans.put(cacheKey, Boolean.FALSE);
;



// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
(targetSource != )
(StringUtils.hasLength(beanName))
.targetSourcedBeans.add(beanName);

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
.proxyTypes.put(cacheKey, proxy.getClass());
proxy;


;

判断是否是aop基础类

是否是aop基础类的判断方法 isInfrastructureClass 如下

@Override
(Class<?> beanClass)
// Previously we setProxyTargetClass(true) in the constructor, but that has too
// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
// aspects. Im not entirely happy with that as there is no good reason not
// to advise aspects, except that it causes advice invocation to go through a
// proxy, and if the aspect implements e.g the Ordered interface it will be
// proxied by that interface and fail at runtime as the advice method is not
// defined on the interface. We could potentially relax the restriction about
// not advising aspects in the future.
// 父类判断它是aop基础类 or 使用@Aspect注解
(.isInfrastructureClass(beanClass) ||
(.aspectJAdvisorFactory != && .aspectJAdvisorFactory.isAspect(beanClass)));

父类判断它是否是aop基础类的方法 super.isInfrastructureClass(beanClass), 本质上就是判断该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口。

(Class<?> beanClass) 
// 该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口
retVal = Advice..() ||
..() ||
..() ||
..();
(retVal && logger.isTraceEnabled())
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");

retVal;

是否应该跳过shouldSkip

通过断点辅助,candidateAdvisors是就是xml配置的通知是对应的

Spring框架系列(9)

@Override
(Class<?> beanClass, String beanName)
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
(Advisor advisor : candidateAdvisors)
(advisor AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName))
;


.shouldSkip(beanClass, beanName);

切面方法转成Advisor

findCandidateAdvisors方法如下:

@Override
List<Advisor> ()
// 在父类中找到所有的advisor:基于xml配置的<aop:before/>生成的
List<Advisor> advisors = .findCandidateAdvisors();
// 为bean Factory中AspectJ切面构建advistor:通过AspectJ注解的方式生成Advisor类
(.aspectJAdvisorsBuilder != )
advisors.addAll(.aspectJAdvisorsBuilder.buildAspectJAdvisors());

advisors;

在当前的bean Factory中通过AspectJ注解的方式生成Advisor类,buildAspectJAdvisors方法如下

/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of @link org.springframework.aop.Advisor beans
* @see #isEligibleBean
*/
List<Advisor> ()
List<String> aspectNames = .aspectBeanNames;

(aspectNames == )
()
aspectNames = .aspectBeanNames;
(aspectNames == )
List<Advisor> advisors = ArrayList<>();
aspectNames = ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
.beanFactory, Object., , );
(String beanName : beanNames)
(!isEligibleBean(beanName))
;

// 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 = .beanFactory.getType(beanName, );
(beanType == )
;

(.advisorFactory.isAspect(beanType))
aspectNames.add(beanName);
AspectMetadata amd = AspectMetadata(beanType, beanName);
(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON)
MetadataAwareAspectInstanceFactory factory =
BeanFactoryAspectInstanceFactory(.beanFactory, beanName);
List<Advisor> classAdvisors = .advisorFactory.getAdvisors(factory);
// 单例加到advisorsCache, 非单例加到aspectFactoryCache
(.beanFactory.isSingleton(beanName))
.advisorsCache.put(beanName, classAdvisors);


.aspectFactoryCache.put(beanName, factory);

advisors.addAll(classAdvisors);


// Per target or per this.
(.beanFactory.isSingleton(beanName))
IllegalArgumentException("Bean with name " + beanName +
" is a singleton, but aspect instantiation model is not singleton");

MetadataAwareAspectInstanceFactory factory =
PrototypeAspectInstanceFactory(.beanFactory, beanName);
.aspectFactoryCache.put(beanName, factory);
// advisorFactory工厂获取advisors
advisors.addAll(.advisorFactory.getAdvisors(factory));



.aspectBeanNames = aspectNames;
advisors;




(aspectNames.isEmpty())
Collections.emptyList();

List<Advisor> advisors = ArrayList<>();
(String aspectName : aspectNames)
List<Advisor> cachedAdvisors = .advisorsCache.get(aspectName);
(cachedAdvisors != )
advisors.addAll(cachedAdvisors);


MetadataAwareAspectInstanceFactory factory = .aspectFactoryCache.get(aspectName);
advisors.addAll(.advisorFactory.getAdvisors(factory));


advisors;

上述方法本质上的思路是:用DCL双重锁的单例实现方式,拿到切面类里的切面方法,将其转换成advisor(并放入缓存中)。

转换的成advisor的方法是:this.advisorFactory.getAdvisors

@Override
List<Advisor> (MetadataAwareAspectInstanceFactory aspectInstanceFactory)
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
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 =
LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

List<Advisor> advisors = ArrayList<>();
(Method method : getAdvisorMethods(aspectClass))
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
(advisor != )
advisors.add(advisor);



// If its a per target aspect, emit the dummy instantiating aspect.
(!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated())
Advisor instantiationAdvisor = SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);


// Find introduction fields.
(Field field : aspectClass.getDeclaredFields())
Advisor advisor = getDeclareParentsAdvisor(field);
(advisor != )
advisors.add(advisor);



advisors;

getAdvisor方法如下

@Override
@Nullable
Advisor (Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
declarationOrderInAspect, String aspectName)

validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
(expressionPointcut == )
;


// 封装成advisor
InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
, aspectInstanceFactory, declarationOrderInAspect, aspectName);

获取表达式的切点

获取表达式的切点的方法getPointcut如下:

@Nullable
AspectJExpressionPointcut (Method candidateAdviceMethod, Class<?> candidateAspectClass)
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
(aspectJAnnotation == )
;


AspectJExpressionPointcut ajexp =
AspectJExpressionPointcut(candidateAspectClass, String[0], Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
(.beanFactory != )
ajexp.setBeanFactory(.beanFactory);

ajexp;

AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod的方法如下

Class<?>[] ASPECTJ_ANNOTATION_CLASSES =  Class<?>[] 
Pointcut., ., ., ., ., .;

/**
* Find and return the first AspectJ annotation on the given method
* (there <i>should</i> only be one anyway...).
*/
@SuppressWarnings("unchecked")
@Nullable
AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method)
(Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES)
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
(foundAnnotation != )
foundAnnotation;


;

findAnnotation方法如下

@Nullable
<A extends Annotation> AspectJAnnotation<A> (Method method, Class<A> toLookFor)
A result = AnnotationUtils.findAnnotation(method, toLookFor);
(result != )
AspectJAnnotation<>(result);


;

AnnotationUtils.findAnnotation 获取注解方法如下

/**
* Find a single @link Annotation of @code annotationType on the supplied
* @link Method, traversing its super methods (i.e. from superclasses and
* interfaces) if the annotation is not <em>directly present</em> on the given
* method itself.
* <p>Correctly handles bridge @link Method Methods generated by the compiler.
* <p>Meta-annotations will be searched if the annotation is not
* <em>directly present</em> on the method.
* <p>Annotations on methods are not inherited by default, so we need to handle
* this explicitly.
* @param method the method to look for annotations on
* @param annotationType the annotation type to look for
* @return the first matching annotation, or @code null if not found
* @see #getAnnotation(Method, Class)
*/
@Nullable
<A extends Annotation> A (Method method, @Nullable Class<A> annotationType)
(annotationType == )
;


// Shortcut: directly present on the element, with no merging needed?
(AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(method))
method.getDeclaredAnnotation(annotationType);


// Exhaustive retrieval of merged annotations...
MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
.get(annotationType).withNonMergedAttributes()
.synthesize(MergedAnnotation::isPresent).orElse();

封装成Advisor

注:Advisor 是 advice的包装器,包含了advice及其它信息

由InstantiationModelAwarePointcutAdvisorImpl构造完成

(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, declarationOrder, String aspectName)

.declaredPointcut = declaredPointcut;
.declaringClass = aspectJAdviceMethod.getDeclaringClass();
.methodName = aspectJAdviceMethod.getName();
.parameterTypes = aspectJAdviceMethod.getParameterTypes();
.aspectJAdviceMethod = aspectJAdviceMethod;
.aspectJAdvisorFactory = aspectJAdvisorFactory;
.aspectInstanceFactory = aspectInstanceFactory;
.declarationOrder = declarationOrder;
.aspectName = aspectName;

(aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated())
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), .declaredPointcut);

// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If its not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
.pointcut = PerTargetInstantiationModelPointcut(
.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
.lazy = ;


// A singleton aspect.
.pointcut = .declaredPointcut;
.lazy = ;
.instantiatedAdvice = instantiateAdvice(.declaredPointcut);

通过pointcut获取advice

Advice (AspectJExpressionPointcut pointcut) 
Advice advice = .aspectJAdvisorFactory.getAdvice(.aspectJAdviceMethod, pointcut,
.aspectInstanceFactory, .declarationOrder, .aspectName);
(advice != ? advice : EMPTY_ADVICE);

交给aspectJAdvisorFactory获取

@Override
@Nullable
Advice (Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, declarationOrder, String aspectName)

// 获取切面类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);

// 获取切面注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
(aspectJAnnotation == )
;


// If we get here, we know we have an AspectJ method.
// Check that its an AspectJ-annotated class
(!isAspect(candidateAspectClass))
AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method " + candidateAdviceMethod + " in class [" +
candidateAspectClass.getName() + "]");


(logger.isDebugEnabled())
logger.debug("Found AspectJ method: " + candidateAdviceMethod);


// 切面注解转换成advice
AbstractAspectJAdvice springAdvice;

(aspectJAnnotation.getAnnotationType())
AtPointcut: // AtPointcut忽略
(logger.isDebugEnabled())
logger.debug("Processing pointcut " + candidateAdviceMethod.getName() + "");

;
AtAround:
springAdvice = AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
;
AtBefore:
springAdvice = AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
;
AtAfter:
springAdvice = AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
;
AtAfterReturning:
springAdvice = AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
(StringUtils.hasText(afterReturningAnnotation.returning()))
springAdvice.setReturningName(afterReturningAnnotation.returning());

;
AtAfterThrowing:
springAdvice = AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
(StringUtils.hasText(afterThrowingAnnotation.throwing()))
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());

;
:
UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);


// 最后将其它切面信息配置到advice
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = .parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
(argNames != )
springAdvice.setArgumentNamesFromStringArray(argNames);

springAdvice.calculateArgumentBindings();

springAdvice;

小结

回头看,主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor的过程。

postProcessAfterInitialization

有了Adisor, 注入到合适的位置并交给代理(cglib和jdk)实现了。

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
Object (@Nullable Object bean, String beanName)
(bean != )
Object cacheKey = getCacheKey(bean.getClass(), beanName);
(.earlyProxyReferences.remove(cacheKey) != bean)
wrapIfNecessary(bean, beanName, cacheKey);


bean;

后文中将分别介绍代理的创建和实现:

总结

通过上文的分析,我们做下小结:

  1. IOC Bean加载方法栈中找到parseCustomElement方法,找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNamespaceHandler)
  2. AopNamespaceHandler注册了<aop:aspectj-autoproxy/>的解析类是AspectJAutoProxyBeanDefinitionParser
  3. AspectJAutoProxyBeanDefinitionParser的parse 方法 通过AspectJAwareAdvisorAutoProxyCreator类去创建
  4. AspectJAwareAdvisorAutoProxyCreator实现了两类接口,BeanFactoryAware和BeanPostProcessor;根据Bean生命周期方法找到两个核心方法:postProcessBeforeInstantiation和postProcessAfterInitialization
  1. postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
  2. postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。

更多文章


首先, 从Spring框架的整体架构和组成对整体框架有个认知。


  • Spring是什么?它是怎么诞生的?有哪些主要的组件和核心功能呢? 本文通过这几个问题帮助你构筑Spring和Spring Framework的整体认知。


其次,通过案例引出Spring的核心(IoC和AOP),同时对IoC和AOP进行案例使用分析。


  • 上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件的典型应用场景和基于这个场景设计出的简单案例,并以此引出Spring的核心要点,比如IOC和AOP等;在此基础上还引入了不同的配置方式, 如XML,Java配置和注解方式的差异。


基于Spring框架和IOC,AOP的基础,为构建上层web应用,需要进一步学习SpringMVC。


  • 前文我们介绍了Spring框架和Spring框架中最为重要的两个技术点(IOC和AOP),那我们如何更好的构建上层的应用呢(比如web 应用),这便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技术基础上,遵循上述Web MVC的规范推出的web开发框架,目的是为了简化Java栈的web开发。 本文主要介绍SpringMVC的请求流程和基础案例的编写和运行。


Spring进阶 - IoC,AOP以及SpringMVC的源码分析


  • 在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解。本文将帮助你站在设计者的角度去看IOC最顶层的结构设计
  • 上文,我们看了IOC设计要点和设计结构;紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的
  • 上文,我们看了IOC设计要点和设计结构;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中存放的是Bean的定义即BeanDefinition放到beanDefinitionMap中,本质上是一个ConcurrentHashMap<String, Object>;并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等。那么如何从BeanDefinition中实例化Bean对象呢,这是本文主要研究的内容?
  • 前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。
  • 上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上继续介绍,代理(cglib代理和JDK代理)的实现过程。
  • 我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。
  • 上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分。
  • 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第一篇:DispatcherServlet的初始化过程的源码解析。
  • 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。

以上是关于Spring框架系列 - Spring AOP实现原理详解之AOP切面的实现的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

Spring框架系列 - 深入浅出Spring核心之面向切面编程(AOP)

死磕Spring AOP系列1:编程式实现AOP

Spring基础系列Spring AOP基础

Spring

Spring系列之AOP的原理及手动实现