AOP 面向切面编程的实现原理

AOP是基于IOC的Bean加载来实现的,所以理解Spring AOP的初始化必须要先理解Spring IOC的初始化。然后就能找到初始化的流程和aop对应的handler,即parseCustomElement方法找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNamespaceHandler)

aop配置标签的解析

AopNamespaceHandler,其实就是注册BeanDefinition的解析器BeanDefinitionParser,将aop:xxxxxx配置标签交给指定的parser来处理。

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.*/@Overridepublic void init() {// In 2.0 XSD as well as in 2.5+ XSDs// 注册解析<aop:config> 配置registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());// 注册解析<aop:aspectj-autoproxy> 配置registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace in 2.5+registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}}

config配置标签的解析

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

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {CompositeComponentDefinition compositeDef =new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));parserContext.pushContainingComponent(compositeDef);configureAutoProxyCreator(parserContext, element);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);}}parserContext.popAndRegisterContainingComponent();return null;
}

parseAspect的方法如下

private void parseAspect(Element aspectElement, ParserContext parserContext) {String aspectId = aspectElement.getAttribute(ID);String aspectName = aspectElement.getAttribute(REF);try {this.parseState.push(new AspectEntry(aspectId, aspectName));List<BeanDefinition> beanDefinitions = new ArrayList<>();List<BeanReference> beanReferences = new ArrayList<>();List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);for (int 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();boolean adviceFoundAlready = false;for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (isAdviceNode(node, parserContext)) {if (!adviceFoundAlready) {adviceFoundAlready = true;if (!StringUtils.hasText(aspectName)) {parserContext.getReaderContext().error("<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",aspectElement, this.parseState.snapshot());return;}beanReferences.add(new 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);for (Element pointcutElement : pointcuts) {parsePointcut(pointcutElement, parserContext);}parserContext.popAndRegisterContainingComponent();}finally {this.parseState.pop();}
}

aspectj-autoproxy配置标签的解析

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

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {// 注册AspectJAnnotationAutoProxyCreatorAopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);// 拓展BeanDefinitionextendBeanDefinition(element, parserContext);return null;
}

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法对应如下

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);registerComponentIfNecessary(beanDefinition, parserContext);
}

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary对应如下

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

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

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

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

如下是类结构关系

它实现了两类接口:

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

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

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

postProcessBeforeInstantiation

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

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {// 如果已经在缓存中,则忽略if (this.advisedBeans.containsKey(cacheKey)) {return null;}// 是否是aop基础类?是否跳过?if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// 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);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;
}
判断是否是aop基础类

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

@Override
protected boolean isInfrastructureClass(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. I'm 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注解return (super.isInfrastructureClass(beanClass) ||(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}

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

protected boolean isInfrastructureClass(Class<?> beanClass) {// 该类是否实现了Advice, Pointcut, Advisor或者AopInfrastructureBean接口boolean retVal = Advice.class.isAssignableFrom(beanClass) ||Pointcut.class.isAssignableFrom(beanClass) ||Advisor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass);if (retVal && logger.isTraceEnabled()) {logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");}return retVal;
}
是否应该跳过shouldSkip

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

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect namesList<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);
}
切面方法转成Advisor

findCandidateAdvisors方法如下:

@Override
protected List<Advisor> findCandidateAdvisors() {// 在父类中找到所有的advisor:基于xml配置的<aop:before/>生成的List<Advisor> advisors = super.findCandidateAdvisors();// 为bean Factory中AspectJ切面构建advistor:通过AspectJ注解的方式生成Advisor类if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return 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*/
public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();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 weaved.Class<?> beanType = this.beanFactory.getType(beanName, false);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);// 单例加到advisorsCache, 非单例加到aspectFactoryCacheif (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);// advisorFactory工厂获取advisorsadvisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames = aspectNames;return advisors;}}}if (aspectNames.isEmpty()) {return Collections.emptyList();}List<Advisor> advisors = new ArrayList<>();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;
}

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

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

@Override
public List<Advisor> getAdvisors(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 =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();for (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);if (advisor != null) {advisors.add(advisor);}}// If it's a per target aspect, emit the dummy instantiating aspect.if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// Find introduction fields.for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;
}

getAdvisor方法如下

@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}// 封装成advisorreturn new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
获取表达式的切点

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

@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}AspectJExpressionPointcut ajexp =new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);ajexp.setExpression(aspectJAnnotation.getPointcutExpression());if (this.beanFactory != null) {ajexp.setBeanFactory(this.beanFactory);}return ajexp;
}

AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod的方法如下

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};/*** Find and return the first AspectJ annotation on the given method* (there <i>should</i> only be one anyway...).*/
@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);if (foundAnnotation != null) {return foundAnnotation;}}return null;
}

findAnnotation方法如下

@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {A result = AnnotationUtils.findAnnotation(method, toLookFor);if (result != null) {return new AspectJAnnotation<>(result);}else {return null;}
}

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
public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType) {if (annotationType == null) {return null;}// Shortcut: directly present on the element, with no merging needed?if (AnnotationFilter.PLAIN.matches(annotationType) ||AnnotationsScanner.hasPlainJavaAnnotationsOnly(method)) {return method.getDeclaredAnnotation(annotationType);}// Exhaustive retrieval of merged annotations...return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()).get(annotationType).withNonMergedAttributes().synthesize(MergedAnnotation::isPresent).orElse(null);
}
封装成Advisor

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

由InstantiationModelAwarePointcutAdvisorImpl构造完成

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {this.declaredPointcut = declaredPointcut;this.declaringClass = aspectJAdviceMethod.getDeclaringClass();this.methodName = aspectJAdviceMethod.getName();this.parameterTypes = aspectJAdviceMethod.getParameterTypes();this.aspectJAdviceMethod = aspectJAdviceMethod;this.aspectJAdvisorFactory = aspectJAdvisorFactory;this.aspectInstanceFactory = aspectInstanceFactory;this.declarationOrder = declarationOrder;this.aspectName = aspectName;if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {// Static part of the pointcut is a lazy type.Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.// If it's not a dynamic pointcut, it may be optimized out// by the Spring AOP infrastructure after the first evaluation.this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);this.lazy = true;}else {// A singleton aspect.this.pointcut = this.declaredPointcut;this.lazy = false;this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}
}

通过pointcut获取advice

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);return (advice != null ? advice : EMPTY_ADVICE);
}

交给aspectJAdvisorFactory获取

@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {// 获取切面类Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();validate(candidateAspectClass);// 获取切面注解AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}// If we get here, we know we have an AspectJ method.// Check that it's an AspectJ-annotated classif (!isAspect(candidateAspectClass)) {throw new AopConfigException("Advice must be declared inside an aspect type: " +"Offending method '" + candidateAdviceMethod + "' in class [" +candidateAspectClass.getName() + "]");}if (logger.isDebugEnabled()) {logger.debug("Found AspectJ method: " + candidateAdviceMethod);}// 切面注解转换成adviceAbstractAspectJAdvice springAdvice;switch (aspectJAnnotation.getAnnotationType()) {case AtPointcut: // AtPointcut忽略if (logger.isDebugEnabled()) {logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");}return null;case AtAround:springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;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;default:throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);}// 最后将其它切面信息配置到advicespringAdvice.setAspectName(aspectName);springAdvice.setDeclarationOrder(declarationOrder);String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);}springAdvice.calculateArgumentBindings();return springAdvice;
}

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
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}

小结

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

  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
    • postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
    • postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。

面试题专栏

Java面试题专栏已上线,欢迎访问。

  • 如果你不知道简历怎么写,简历项目不知道怎么包装;
  • 如果简历中有些内容你不知道该不该写上去;
  • 如果有些综合性问题你不知道怎么答;

那么可以私信我,我会尽我所能帮助你。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/494395.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Java开发环境搭建二、VScode下载及安装三、VSCode配置Java环境四、运行测试五、背景图设置 很高兴你打开了这篇博客&#xff0c;更多详细的安装教程&…

【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…

Go怎么做性能优化工具篇之基准测试

一、什么是基准测试&#xff08;Benchmark&#xff09; 在 Go 中&#xff0c;基准测试是通过创建以 Benchmark 开头的函数&#xff0c;并接收一个 *testing.B 类型的参数来实现的。testing.B 提供了控制基准测试执行的接口&#xff0c;比如设置测试执行的次数、记录每次执行的…

vulnhub靶场【WhowWantsToBeKing】之1

前言 靶机&#xff1a;whowantstobeking-1&#xff0c;ip地址192.168.1.67 攻击&#xff1a;kali &#xff0c;ip地址192.168.1.16 主机发现 使用arp-sacn -l或者netdiscover -r 192.168.1.1/24扫描 信息收集 使用nmap扫描端口 网站信息探测 访问80端口默认界面&#xff…

Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】

JAVA最新版JDK 23 安装教程详解 Java Development Kit (JDK) 23 是Oracle发布的最新长期支持版本 (LTS) 之一&#xff0c;它带来了许多新特性和改进。 本教程将详细介绍如何在Windows、macOS和Linux系统上安装JDK 23&#xff0c;并涵盖一些常见问题和解决方法。 一、 准备工作…

set的使用

文章目录 一、关联式容器二、set1、set的介绍2、set的使用2.1、元素的插入&#xff08;insert接口&#xff09;2.2、pair的简单讲解2.3、元素的查找&#xff08;find接口&#xff09;2.4、判断元素是否在set中&#xff08;count接口&#xff09;2.5、元素的删除&#xff08;era…

[Xshell] Xshell的下载安装使用、连接linux、 上传文件到linux系统-详解(附下载链接)

前言 xshell 链接&#xff1a;https://pan.quark.cn/s/57062561e81a 提取码&#xff1a;TK4K 链接失效&#xff08;可能被官方和谐&#xff09;可评论或私信我重发 安装 下载后解压得到文件 安装路径不要有中文 打开文件 注意&#xff01;360等软件会拦截创建注册表的行为&a…

基于蜂鸟视图的智慧可视化巡检管理系统研究

摘要 本文围绕蜂鸟视图研发的智慧可视化巡检管理系统展开研究&#xff0c;系统依托室内地图和室内定位技术&#xff0c;覆盖“规划、巡场、检查、上报”的完整业务流程。核心功能包括基于蓝牙定位的巡检点位置验证、可视化巡场地图的在线规划与导航、以及巡检路线轨迹的回放分析…

GUI07-学工具栏,懂MVC

MVC模式&#xff0c;是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时&#xff0c;就是他的一生中&#xff0c;最适合开始认识 MVC 模式的好时机之一。这节将安排您学习&#xff1a; Model-View-Controller 模式如何创建工具栏以及…

Chrome 关闭自动添加https

Open Chrome and go to “chrome://net-internals/#hsts”

重拾设计模式--外观模式

文章目录 外观模式&#xff08;Facade Pattern&#xff09;概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式&#xff08;Facade Pattern&#xff09;概述 定义 外观模式是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供了一个统一…

gitlab代码推送

点击这个√ 修改的文件全部选上 填好提交的名称 点击commit 选取提交的 gitlab 库 点击Push

echarts画风向杆

1.安装echarts 2.引入echarts 4.获取数据&#xff0c;转换数据格式 windProfile.title.text ${moment(time.searchTime[0], ‘YYYY-MM-DD HH:mm:ss’).format( ‘YYYY-MM-DD HH:mm’ )}-${moment(time.searchTime[1], ‘YYYY-MM-DD HH:mm:ss’).format(‘YYYY-MM-DD HH:mm’)…

Java字符串的|分隔符转List实现方案

字符串处理 问题背景代码实现代码优化原因分析实现方案 注意事项异常处理Maven未识别异常 问题背景 在项目组对账流程中&#xff0c;接收对方系统的对账文件&#xff0c;数据以|为分隔符&#xff0c;读取文件内容&#xff0c;分条入库。 代码实现 Java中将字符串转给list&am…

「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台

本篇将带你实现一个虚拟音乐控制台。用户可以通过界面控制音乐的播放、暂停、切换歌曲&#xff0c;并查看当前播放的歌曲信息。页面还支持调整音量和动态显示播放进度&#xff0c;是音乐播放器界面开发的基础功能示例。 关键词 UI互动应用音乐控制播放控制动态展示状态管理按钮…

iOS从Matter的设备认证证书中获取VID和PID

设备认证证书也叫 DAC, 相当于每个已经认证的设备的标识。包含了 VID 和 PID. 根据 Matter 对于设备证书的规定&#xff0c;DAC证书subject应该包含VID 和 PID. 可通过解析 X509 证书读取subject 来获得信息。 1 通过 SPM 添加X509 git地址&#xff1a;https://github.com/ap…

计算机毕业设计PyFlink+Hadoop广告推荐系统 广告预测 广告数据分析可视化 广告爬虫 大数据毕业设计 Spark Hive 深度学习 机器学

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

(2024.12)Ubuntu20.04安装openMVS<成功>.colmap<成功>和openMVG<失败>记录

一、安装openMVS 官方文档&#xff1a;https://github.com/cdcseacave/openMVS/wiki/Building sudo apt-get -y install git mercurial cmake libpng-dev libjpeg-dev libtiff-dev libglu1-mesa-dev eigen git clone https://gitlab.com/libeigen/eigen --branch 3.4 mkdi…

UE5 猎户座漂浮小岛 12 技能 瞬移 重力控制

1. 瞬移 1.1. 显示鼠标光标 “事件开始运行”添加显示鼠标逻辑 1.2. 释放技能蓝图 设置技能键 编写蓝图 1.3. 瞬移最大距离 2. 重力控制 2.1. 添加输入与动画 映射 重定向得到动画 新增状态FIRE_GracityControl 设置动画姿势 新增变量 切换动画 2.2. 技能蓝图&#xff08;…

叉车作业如何确认安全距离——UWB测距防撞系统的应用

叉车在工业环境中运行&#xff0c;常常需要在狭窄的空间内完成货物的搬运和堆垛&#xff0c;这对操作员的技术水平和安全意识提出了极高的要求。传统的叉车作业依赖操作员的经验和视觉判断来确认安全距离&#xff0c;然而这种方式往往存在误差&#xff0c;特别是在视线受阻或光…