编程知识 cdmana.com

Spring AOP core class analysis, this is the most complete one!!

In the high concurrency scenario, the author has developed it , Simple to offer 、 Stable 、 Extensible delayed message queuing framework , It has precise timing task and delay queue processing function . Since the open source for more than half a year , It has successfully provided precise timing scheduling scheme for more than ten small and medium-sized enterprises , It has withstood the test of production environment . In order to benefit more children's shoes , Now give the open source framework address :

https://github.com/sunshinelyz/mykit-delay

PS: Welcome to Star Source code , It's fine too pr Your blazing code .

Write it at the front

lately , Many of my friends are pushing for more 【Spring Annotation driven development 】 project , ok ,【Spring Annotation driven development 】 The topic has not been updated for a long time . So we'll update it from today 【Spring Annotation driven development 】 project , alike , We still focus on source code analysis . The article has been synchronized to :https://github.com/sunshinelyz/technology-binghe and https://gitee.com/binghe001/technology-binghe . If the document is of some help to you , Don't forget to give it Star Oh ! Focus on 【 Glacier Technology 】 WeChat official account , reply “Spring annotation ” Get project source code .

Class structure diagram

So let's see AnnotationAwareAspectJAutoProxyCreator Class structure diagram .

Some of the above class / Interface Introduction to :

AspectJAwareAdvisorAutoProxyCreator : It's public AspectJ Call context of , And find out more than one from the same section Advisor stay AspectJ Priority rules in .

AbstractAdvisorAutoProxyCreator : General automatic proxy Creator , It is based on each advisor detected for a specific bean structure AOP agent .

AbstractAutoProxyCreator : Expanded ProxyProcessorSupport, Realized SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware Interface , yes BeanPostProcessor Realization , The implementation uses AOP Agent package each qualified bean, And in the call bean Assigned to the designated interceptor before itself .

BeanFactoryAware : Implements the interface of Bean You know it belongs to that BeanFactory,Bean Can pass Spring The container finds its collaborators ( Dependency lookup ), But most of Bean Through constructor parameters and Bean Method ( Dependency injection ) To get its collaborators .

BeanPostProcessor : Factory hooks , Allow customization to modify new bean example . for example , Check the tag interface or use proxy wrapping bean. If we need to Spring Done in container Bean Instantiation , Configuration and its initialization before and after adding some of its own logic processing , We can define one or more BeanPostProcessor Interface implementation , Then register in the container .

InstantiationAwareBeanPostProcessor : BeanPostProcessor Sub interface of , It adds a callback before instantiation , And callbacks after instantiation but before setting explicit properties or automatic assembly . It's provided internally 3 A way , Plus BeanPostProcessor interfacial 2 A way , To implement this interface, you need to implement 5 A way .InstantiationAwareBeanPostProcessor The main function of an interface is what needs to be done during the instantiation of the target object , This includes the before and after process of instantiating the object and setting the properties of the instance .

SmartInstantiationAwareBeanPostProcessor : InstantiationAwareBeanPostProcessor Interface extension , There's more 3 A way , Added for forecasting processed bean The final type of callback , Plus the parent interface 5 A way , So implementing this interface requires implementation 8 A way , The main function is to deal with things in the instantiation process of the target object .

All in all :AspectJAwareAdvisorAutoProxyCreator by AspectJ Facet classes create automatic proxies .

Core class parsing

BeanPostProcessor Two methods in the interface postProcessBeforeInitialization and postProcessAfterInitialization, The effect is right. Bean Before and after initialization Add your own logic .

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

InstantiationAwareBeanPostProcessor yes BeanPostProcessor Sub interface of , It adds extra 3 A new way :postProcessBeforeInstantiation( The target object is Before instantiation Method called , A proxy that can return the target instance is used instead of the target instance )、postProcessAfterInstantiation( The method in Bean After instantiation perform , return false, The setting of the property value will be ignored ; If you return true, The property values are set according to the normal process ) and postProcessPropertyValues( Modify the property value , Future versions will delete )

@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
}

@Nullable
default PropertyValues postProcessPropertyValues(
    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    return pvs;
}

SmartInstantiationAwareBeanPostProcessor Interface inheritance InstantiationAwareBeanPostProcessor Interface , It's defined in it 3 A way :predictBeanType( forecast Bean The type of )、determineCandidateConstructors( Select the appropriate constructor )、getEarlyBeanReference( Solve the problem of circular reference ).

@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
    return null;
}

default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    return bean;
}

AbstractAutoProxyCreator yes AOP A core class of , It has achieved SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware Interface , The logic of agent creation is realized , Use AOP Agent package each qualified bean, And in the call bean Assigned to the designated interceptor before itself .

AbstractAdvisorAutoProxyCreator General automatic proxy Creator , It's based on detecting each bean The intensifier of , For special bean structure AOP agent . Subclasses can override this findCandidateAdvisors() Method , To return... That applies to any object advisor Custom list of , Subclasses can also override inherited AbstractAutoProxyCreator.shouldSkip() Method , To exclude certain objects from automatic proxies .

protected List<Advisor> findCandidateAdvisors() {
       Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
     return this.advisorRetrievalHelper.findAdvisorBeans();
}

AspectJAwareAdvisorAutoProxyCreator Expand AbstractAdvisorAutoProxyCreator, It's public AspectJ Call context of , And when multiple enhancers come from the same section AspectJ The suggested priority order for . Press AspectJ The rest of the prioritization :

@Override
@SuppressWarnings("unchecked")
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
    for (Advisor element : advisors) {
        partiallyComparableAdvisors.add(
            new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        return super.sortAdvisors(advisors);
    }
}

Add a... To the head of the reinforcement chain ExposeInvocationInterceptor, Use AspectJ Expression pointcuts and uses AspectJ Styling advisor when , You need these additions advisor.

protected void extendAdvisors(List<Advisor> candidateAdvisors) {
      AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

If after that, the processor should not consider the given bean For auto proxy , Subclasses should override this method to return true

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

AspectJAwareAdvisorAutoProxyCreator There is also a subclass called AnnotationAwareAspectJAutoProxyCreator, Subclass AnnotationAwareAspectJAutoProxyCreator Is used to handle all of the AspectJ In terms of annotation and Spring Advisor. If Spring AOP The agent-based model of can apply any AspectJ Annotated classes , Their advisor Will be automatically identified , This covers method execution join points ,Spring Advisor The treatment of is in accordance with AbstractAdvisorAutoProxyCreator The rules established in .

Generate proxy objects

From using aop:xxx Tag to automatically generate agents , Have a look first AopNamespaceHandler, Use aop:config The label uses ConfigBeanDefinitionParser analysis , Used aop:aspectj-autoproxy The label uses AspectJAutoProxyBeanDefinitionParser analysis , By analogy .

@Override
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.1
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
  • aop:config Way to use AspectJAwareAdvisorAutoProxyCreator To create the agent
  • aop:aspectj-autoproxy Use AnnotationAwareAspectJAutoProxyCreator To create the agent

ConfigBeanDefinitionParser.java

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

    configureAutoProxyCreator(parserContext, element); //  register AspectJAwareAdvisorAutoProxyCreator

    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;
}

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

AopConfigUtils.java

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

    configureAutoProxyCreator(parserContext, element); //  register AspectJAwareAdvisorAutoProxyCreator

    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;
}

private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

AopConfigUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    //  Registered here is AspectJAwareAdvisorAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext); //  Certified components 
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {

    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

AspectJAwareAdvisorAutoProxyCreator Realized BeanPostProcessor Wait for the interface described above , Mainly for Bean Before and after initialization , Before and after instantiation , be-all Bean Are affected .InstantiationAwareBeanPostProcessor yes BeanPostProcessor Sub interface of , But it's called at a point in time Bean Before instantiation , In the real call doCreateBean() establish bean Execute before instance postProcessBeforeInstantiation().

AbstractAutoProxyCreator.java

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);  //  Get a cache of the only key( according to beanClass and beanName Generating uniqueness key)
    //  If at present targetSourcedBeans( By customizing TargetSourceCreator Created TargetSource) It doesn't contain cacheKey
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {  //advisedBeans( Has been enhanced Bean, namely AOP Proxy object ) Contains the current cacheKey, return null, That is to say Spring Default process 
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {//  If it's infrastructure ( Such as Advisor、Advice、AopInfrastructureBean The implementation of the ) No processing ;( A little )
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    //  If there is a custom TargetSource, Create a proxy here 
    //  Forbidden target Bean Unnecessary default instantiation of :
    // TargetSource The target instance will be processed in a custom way .
    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;
}

adopt AbstractAutoProxyCreator Medium postProcessAfterInitialization() establish AOP agent .

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {  //  If I have called before getEarlyBeanReference Get the wrapper target object to AOP Proxy object ( if necessary ), No more execution 
            return wrapIfNecessary(bean, beanName, cacheKey);  //  Package the target object to AOP Proxy object ( if necessary )
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { //  adopt TargetSourceCreator Customize TargetSource There's no need for packaging 
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {  //  Objects that should not be enhanced do not need to be wrapped 
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { //  Infrastructure may or should be skip You don't have to guarantee 
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    //  If there is advise Then create an agent .
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); //  Create proxy object 
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

Okay , That's all for today , I'm glacier , See you next time ~~

This article is from WeChat official account. - Glacier Technology (hacker-binghe)

The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

Original publication time : 2020-12-04

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[glacier]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224160737111k.html

Scroll to Top