Writing in the front

Recently, a lot of people have been calling for the “Spring Annotation-driven Development” topic to be updated. Well, the “Spring annotation-driven Development” topic has not been updated for a long time. We will update the Spring Annotation-driven Development topic today, and again, we will focus on source code parsing.

The article has been included: github.com/sunshinelyz… And gitee.com/binghe001/t… . If the file is helpful, don’t forget to give a Star!

Follow [Glacier Technology] wechat official account, reply “Spring notes” to get the project source code.

Class diagram

Let’s look at AnnotationAwareAspectJAutoProxyCreator class structure.

An introduction to some of the classes/interfaces shown above:

AspectJAwareAdvisorAutoProxyCreator: open the AspectJ invocation context, and find out from all the multiple Advisor in AspectJ priority rules.

AbstractAdvisorAutoProxyCreator: general automatic proxy creator, it based on the detected each advisor for specific bean building AOP agent.

AbstractAutoProxyCreator : Expanded the ProxyProcessorSupport, has realized the SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware interface, is a BeanPostProcessor implementations, The implementation uses an AOP proxy to wrap each qualifying bean and delegate to the specified interceptor before calling the bean itself.

BeanFactoryAware : A Bean that implements this interface can know which BeanFactory it belongs to, and a Bean can look up its collaborators (dependency lookup) through the Spring container, but most beans get their collaborators through constructor arguments and Bean methods (dependency injection).

BeanPostProcessor: Factory hook that allows you to customize new bean instances. For example, check the tag interface or use a proxy to wrap beans. If we need to instantiate a Bean in the Spring container, add some of our own logic before and after configuration and initialization, we can define one or more implementations of the BeanPostProcessor interface and register them with the container.

InstantiationAwareBeanPostProcessor: BeanPostProcessor interface, it added before instantiating the callback, and instantiated but set the explicit attribute or automatic assembly before the callback. It provides three methods internally, plus two methods internally from the BeanPostProcessor interface, which requires five methods to implement. InstantiationAwareBeanPostProcessor interface is the main function of the target object in the process of the instantiation of the need to deal with things, including process before and after the instantiation object and instance attribute set.

SmartInstantiationAwareBeanPostProcessor : InstantiationAwareBeanPostProcessor interface extension, more out of the three methods, add the prepared bean is used to predict the final type of callback, coupled with the five methods of the interface, the father so implement this interface to implement the eight methods, The main function is also something that needs to be handled during the instantiation of the target object.

In short: AspectJAwareAdvisorAutoProxyCreator create automatic proxy for AspectJ aspect class.

Core Class resolution

BeanPostProcessor interface of the two methods postProcessBeforeInitialization and postProcessAfterInitialization, before and after the Bean initialization function is to add some logic of their own.

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

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

InstantiationAwareBeanPostProcessor BeanPostProcessor as part of the interface, it for an additional three new methods: PostProcessBeforeInstantiation (the target object is instantiated before calling the method, can return to the target instance of an agent used in place of the target instance), postProcessAfterInstantiation (the method after Bean instantiation, Returns false, ignoring the property value; If returns true, you will be in accordance with the normal process set attribute value) and postProcessPropertyValues (modify attribute values and 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;
}
Copy the code

SmartInstantiationAwareBeanPostProcessor interface inheritance InstantiationAwareBeanPostProcessor interface, which defines three methods: PredictBeanType (predict the type of Bean), determineCandidateConstructors (choosing the appropriate constructor), getEarlyBeanReference (solve the problem of circular references).

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

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

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

AbstractAutoProxyCreator is a core class of AOP, it implements the SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware interface, realize the logic of the agent to create, Wrap each qualifying bean with an AOP proxy and delegate to the specified interceptor before calling the bean itself.

AbstractAdvisorAutoProxyCreator general automatic proxy creator, it is based on testing each bean enhancer, for special bean building AOP agent. Subclasses can override this findCandidateAdvisors () method to return is applicable to any object advisor custom list,. Subclasses can override inherited AbstractAutoProxyCreator shouldSkip () method, To exclude certain objects from automatic proxies.

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

AspectJAwareAdvisorAutoProxyCreator extension AbstractAdvisorAutoProxyCreator, open the AspectJ invocation context, And figure out how To prioritize AspectJ’s recommendations when multiple enhancers come from the same aspect. Sort the rest by AspectJ priority:

@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); }}Copy the code

In strengthen the chain add a ExposeInvocationInterceptor head, use AspectJ expression using AspectJ style of advisor, and approach to need these additional advisor.

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

Subclasses should override this method to return true if the processor should not later consider using the given bean for automatic proxy

@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);
}
Copy the code

AspectJAwareAdvisorAutoProxyCreator and a subclass called AnnotationAwareAspectJAutoProxyCreator, Subclasses AnnotationAwareAspectJAutoProxyCreator the current application context is used to handle all the AspectJ annotation aspect and the Spring Advisor. If Spring AOP’s proxy-based model can apply any AspectJ-annotated classes, their advisors will be automatically recognized, covering method execution join points, The processing of the Spring Advisor follows the established rules in AbstractAdvisorAutoProxyCreator.

Generating proxy objects

Tags to automatically generate from using aop: XXX agent, first take a look at AopNamespaceHandler, using aop: use the ConfigBeanDefinitionParser parse the config label, Using the aop: aspectj – use the AspectJAutoProxyBeanDefinitionParser analytic autoproxy label, so on.

@Override
public void init(a) {
    // 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());
}
Copy the code
  • Aop: config mode using AspectJAwareAdvisorAutoProxyCreator create proxies
  • Aop: use aspectj – autoproxy AnnotationAwareAspectJAutoProxyCreator create proxies

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);
}
Copy the code

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);
}
Copy the code

AopConfigUtils.java

public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) {
    / / is AspectJAwareAdvisorAutoProxyCreator registered here
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext); // Register the component
}
Copy the code
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {

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

AspectJAwareAdvisorAutoProxyCreator implements the BeanPostProcessor interface described above, such as, before, during and after the main role in Bean initialization instantiation, before and after all the beans are to action. InstantiationAwareBeanPostProcessor BeanPostProcessor as part of the interface, but its call time point before the Bean is instantiated, In real call doCreateBean () to create the bean instance before execution postProcessBeforeInstantiation ().

AbstractAutoProxyCreator.java

@Override
public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName);// Get a unique key for the cache (from beanClass and beanName)
    // If the current targetSourcedBeans (a TargetSource created with a custom TargetSourceCreator) do not contain cacheKey
    if(! StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {//advisedBeans (enhanced beans that are AOP proxy objects) contain the current cacheKey, which returns NULL, following the Spring default process
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {// If the infrastructure class (such as Advisor, Advice, AopInfrastructureBean implementation) is not processed; (abbreviated)
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null; }}// Create the proxy here if you have a custom TargetSource
    // Disallow unnecessary default instantiation of the target Bean:
    // TargetSource will handle the target instance in a custom manner.
    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;
}
Copy the code

Through the postProcessAfterInitialization AbstractAutoProxyCreator (AOP) creation 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 getEarlyBeanReference was previously called to get the wrapped target object into the AOP proxy object (if needed), it is no longer executed
            returnwrapIfNecessary(bean, beanName, cacheKey);// Wrap the target object into an AOP proxy object (if required)}}return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { // Customizing TargetSource with TargetSourceCreator does not require wrapping
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {// Objects that should not be enhanced need not be wrapped
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // Infrastructure or should skip does not need to be guaranteed
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create the agent if there is advise.
    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 a proxy object
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

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

Ok, that’s enough for today. I’m Glacier. See you next time

Glacier Original PDF

Follow Glacier Technology wechat official account:

Reply to “Concurrent Programming” to receive the PDF of In-depth Understanding of High Concurrent Programming (1st edition).

Reply “concurrent source code” to get the “Concurrent programming core Knowledge (source code Analysis first edition)” PDF document.

Reply to “Limit Traffic” to get the PDF document “Distributed Solution under 100 million Traffic”.

Reply to “design patterns” to get the PDF of “simple Java23 design patterns”.

Reply “new Java8 features” obtain the Java8 new features tutorial PDF document.

Reply to “Distributed Storage” to receive the PDF of “Learn Distributed Storage Techniques from Glacier”.

Reply to “Nginx” to receive the PDF of Learn Nginx Technology from Glacier.

Reply to “Internet Engineering” to get the PDF of “Learn Internet Engineering techniques from Glacier”.

Big welfare

WeChat search the ice technology WeChat 】 the public, focus on the depth of programmers, daily reading of hard dry nuclear technology, the public, reply within [PDF] have I prepared a line companies interview data and my original super hardcore PDF technology document, and I prepared for you more than your resume template (update), I hope everyone can find the right job, Learning is a way of unhappy, sometimes laugh, come on. If you’ve worked your way into the company of your choice, don’t slack off. Career growth is like learning new technology. If lucky, we meet again in the river’s lake!

In addition, I open source each PDF, I will continue to update and maintain, thank you for your long-term support to glacier!!

Write in the last

If you think glacier wrote good, please search and pay attention to “glacier Technology” wechat public number, learn with glacier high concurrency, distributed, micro services, big data, Internet and cloud native technology, “glacier technology” wechat public number updated a large number of technical topics, each technical article is full of dry goods! Many readers have read the articles on the wechat public account of “Glacier Technology” and succeeded in job-hopping to big factories. There are also many readers to achieve a technological leap, become the company’s technical backbone! If you also want to like them to improve their ability to achieve a leap in technical ability, into the big factory, promotion and salary, then pay attention to the “Glacier Technology” wechat public account, update the super core technology every day dry goods, so that you no longer confused about how to improve technical ability!