The introduction of

Before explaining the solution to cyclic dependencies, we must have some knowledge of AOP's source code, because the secondary caching involved in cyclic dependencies is related to AOP source code, which is appropriately pruned during source code analysis (e.glogLogs and some code that doesn't affect the main line)Copy the code

Analysis of the steps that invoke the post-processor to complete the AOP initialization

Analyze the initialization effort as a whole

Start with the entry code to create the singleton bean
if (mbd.isSingleton()) {
  sharedInstance = getSingleton(beanName, () -> {
    returncreateBean(beanName, mbd, args); }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } As you can see, the bean is eventually created by calling the createBean method; in other words, the method in the LAMda expression is called in the getSingleton method, thus starting the process of creating the beanCopy the code
CreateBean (); createBean ()
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) {
  // Parse to get the bean's corresponding class objectRootBeanDefinition mbdToUse = mbd; Class<? > resolvedClass = resolveBeanClass(mbd, beanName);Execute the bean's post-processor once before actually creating the bean
  // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
  Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  if(bean ! =null) {
    return bean;
  }

  // Start the actual bean creation
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  returnbeanInstance; } analysis: As you can see, before the bean is actually created, that is, before the doCreateBean is called, the bean's post-processor is called to parse it. As you can see from the English comments in the source code, Given a chance to return a proxy object to replace the target bean instance with BeanPostProcessors, we might wonder, isn't this where AOP proxy objects are generated? It's not. It's for programmers to extend. If we implement a proxy logic ourselves, we can return an object when we do a post-processor here, so Spring doesn't have to create bean objects. Take a look at the next resolveBeforeInstantiation methodCopy the code
Three, founded by resolveBeforeInstantiation method to see in real bean before the operation of the Spring
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  Object bean = null;
  The beanDefinition variable is set to true when the bean object is generated by the post-processor
  if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {/ / if the bean is not synthetic, which generated by the application itself, and have InstantiationAwareBeanPostProcessor
    // If the post-processor is in the container, the post-processor will be called
    if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
        // Start calling the before method of the post-processor. If the method returns an object, then the bean object has been created
        Spring does not create bean objects. In other words, Spring does not create bean objects.
        // The after method is not normally called. When we implement the post-processor and write the proxy logic ourselves,
        // The after method is called
        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        if(bean ! =null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
  }
  returnbean; } analysis: the whole resolveBeforeInstantiation method is the most core applyBeanPostProcessorsBeforeInstantiation method calls, under normal circumstances, the return value of this methodnullThe afterInitialization method is called only when the method returns a bean object. In other words, the before method of the afterInitialization is called before the bean object is created. Call the post-processor's after method after the bean is created. Spring provides this extension point for programmers to implement their own proxy logic at this point in time, according to the Previous English comment. Next we see applyBeanPostProcessorsBeforeInstantiation method callCopy the code
Four, applyBeanPostProcessorsBeforeInstantiation method calls post processor
protected Object applyBeanPostProcessorsBeforeInstantiation(Class
        beanClass, String beanName) {
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
      if(result ! =null) {
        returnresult; }}}return null; } analysis: The main job is to call InstantiationAwareBeanPostProcessor applyBeanPostProcessorsBeforeInstantiation method The post processor postProcessBeforeInstantiation method that allow programmers to implement your own here agent logic, all through the post processor implementation class as you can see, basically is to returnnull
Copy the code

AbstractAutoProxyCreator postProcessBeforeInstantiation method

A, postProcessBeforeInstantiation method
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;
    }

    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return null; }}return null; } analysis: for all InstantiationAwareBeanPostProcessor implementation class, you can go to check one by one, will find that almost all of this method in the implementation class are returnednullBecause there is no need to create a bean at this point in time, which Spring provides for programmers to extend their own proxy logic, but for AOP's implementation principle, a core class abstractautoXyCreator implements this method in addition to returningnullIn addition, there are a few additional things that are closely related to AOP that AOP does at this point: The first thing we need to understand is that when we turn on AOP, all BeanDefinitions will execute to the before method, so all BeanDefinitions will make these judgments.1> Object cacheKey = getCacheKey(beanClass, beanName);2> advisedBeans, this property is a Map<Object, Boolean> that stores all classes that are not judged by an AOP proxy as well as classes that have already been propped up by an AOP proxy. If the former, then value isfalseIf the latter, then value istrue

  <3Word-wrap: break-word! Important; "> < p style =" max-width: 100%@AspectThe annotation indicates that it is a facet class, so AOP must not be proxying a facet class. This is so-called AOP proxy-free class, and the most important function of the before method is that when each beanDefinition calls the method, Filter out all classes that are not judged by an AOP proxy and put them into the advisedBeans map.4> But a bean that is not included by AOP's PointCut will still be put into the advisedBean with a value offalseIn other words, in this Map, when value istrueIs the object that needs to be proxied by AOP, and value isfalseIs not, at the moment, only some special objects (such as by@AspectAnnotation annotation object) is put here, and value is equal tofalse, only when the proxy object is created, when the proxy object is put into the Map, the corresponding value istrue
  <5We use the shouldSkip method to do two things. The first is to scan the entire container for the notification classes@AspectAnnotation class), and the notification class in the notification class, the name of the notification class and the notification class in the cache, later when AOP can be used directlyCopy the code
IsInfrastructureClass filters out all notification classes
/ / call AnnotationAwareAspectJAutoProxyCreator isInfrastructureClass
protected boolean isInfrastructureClass(Class
        beanClass) {
  return (super.isInfrastructureClass(beanClass) ||
      (this.aspectJAdvisorFactory ! =null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}

Call isInfrastructureClass abstractautoXyCreator isInfrastructureClass
protected boolean isInfrastructureClass(Class
        beanClass) {
  boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
      Pointcut.class.isAssignableFrom(beanClass) ||
      Advisor.class.isAssignableFrom(beanClass) ||
      AopInfrastructureBean.class.isAssignableFrom(beanClass);
  returnretVal; } From the above code, you can see that the isInfrastructureClass method is encountered by a class@AspectAnnotation annotations and subclasses of Pointcut, Advice, Advisor, AopInfrastructureBean are returnedtrue
Copy the code
ShouldSkip method
protected boolean shouldSkip(Class
        beanClass, String beanName) {
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  for (Advisor advisor : candidateAdvisors) {
    if (advisor instanceof AspectJPointcutAdvisor &&
        ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
      return true; }}return super.shouldSkip(beanClass, beanName); } analysis: What Spring does in the findCandidateAdvisors method is to find all the notification classes and the notification methods in those classes, and then belowforIf a notification is of type AspectJPointcutAdvisor (which is not usually the case) and the notification has the same aspect name as the bean name, it should also be skipped. Then call the parent's shouldSkip method. In the parent's method, If a class is ORIGINAL or not, all we need to know here is that shouldSkip does a scan of all notification classes and methods and caches themCopy the code

FindCandidateAdvisors method analysis

findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors(a) {
  // Add all the Spring advisors found according to superclass rules.
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  if (this.aspectJAdvisorsBuilder ! =null) {
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  returnadvisors; } analysis: The whole findCandidateAdvisors method is to find all the notifications and cache them forsuperThe.findcandidateAdvisors () method iterates through the Advisor class in the container. If an instance of the class has not been created, the getBean method will be used to create the instance. Then putting them in the List and returning the buildAspectJAdvisors method is the way to start building our own advice, putting them in the cache, and then returning them to integrate the advisors from the previous step, which is to find all the advice advisorsCopy the code
The buildAspectJAdvisors method builds the notification provided by the programmer
public List<Advisor> buildAspectJAdvisors(a) {
  List<String> aspectNames = this.aspectBeanNames;

  if (aspectNames == null) {... Start building...... }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)); }}returnadvisors; } Analysis: To look at the method as a whole, Spring first fetches all the files from the cache@AspectAnnotated class beanName, if not in the cache, inifThe judgment will start looking for all the@AspectThe annotated class, meanwhile, parses the notification inside, turns it into an Advisors, and then puts it in the cache, in other words, in the entireifIn judgment, two things are done, the first is to find all the quilt@AspectThe labeled class, the second is to parse the notification method inside, turn it into one Advisor, and then cache the results of these two things respectively.@AspectThe beanName of the tagged class is cachedthis.aspectBeannames, the parsed Advisor is cachedthis.Advisorscache, this is a Map, the key is beanName, the value is a List, it stores all of the notification methods for this bean, and then returns all of the notifications if it's in the cache, it won't go inifInside, and Spring starts iterating through one by one@AspectAnnotated beanName, and then based on that beanName it gets notifications from advisorsCache, consolidates all notifications and returns themifThe inside of the code -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- a List < Advisor > advisors =new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    this.beanFactory, Object.class, true.false); Spring uses BeanFactoryUtils to fetch all beannames from the container by typefor(String beanName : beanNames) { Class<? > beanType =this.beanFactory.getType(beanName);
  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); }}}this.aspectBeanNames = aspectNames;
returnadvisors; Analysis: Spring traverses all beans if the bean is@AspectAnnotations are annotated, then they are added to aspectNames, and as you can see at the end, Spring will add all of the annotations@AspectMarked with the class beanName cached, at the same time, the Spring created a MetadataAwareAspectInstanceFactory beanName as parameters, All notifications in the bean are parsed using advisorFactory's getAdvisors method. After parsing, they are put into advisorsCache. Finally, all notifications are returned to getAdvisors. Spring iterates through all the methods in the bean to find the notified annotation (e.g@BeforeAnnotation method, encapsulate it into one Advisor after another and returnCopy the code
Summary
In the findCandidateAdvisors method, Spring scans all the classes in the container, finds all the notification classes and notification methods, cages the results, and also finds classes of type Advisor in the container (which are also notifications)Copy the code

Summary

The first call to post processor to complete the initialization of AOP postProcessBeforeInstantiation InstantiationAwareBeanPostProcessor will eventually call interface method, This method is an extension point that Spring provides to developers, allowing them to implement their own proxy logic without using Spring's proxy logic. However, some AOP initialization is also done in the implementation class of this method, which filters all BeanDefinitions. The classes that are not filtered through AOP proxies are put into a Map of advisedBeans. At the same time, on the first call to the post-processor, the first BD in the container goes to the post-processor, the bd in the container is scanned for all the advice classes and advice. Cache themCopy the code

AOP implementation principle step analysis

Simple analysis of doCreateBean

On AOP initialization can be seen in the second step, after calling the resolveBeforeInstantiation completed AOP initialization, call the doCreateBean method, next we simply to explain the methodprotected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
  // Instantiate the bean
  BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);

  finalObject bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass(); Object exposedObject = bean; populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); .returnexposedObject; } analysis: The doCreateBean method involves a lot of work, including the solution to loop dependencies and property injection, which we will cover in detail in a later section. Here we remove a lot of the code and extract only a portion of the code to introduce AOP's true execution logic.1The createBeanInstance method is what Spring actually uses to create a bean object. In this method, Spring also uses a post-processor to determine which constructor to use to create a bean object. This was briefly mentioned in the previous bean post-processor section. After the object is created, a BeanWrapper wrapper is returned, and the bean object and its corresponding Class object are retrieved by calling getWrappedInstance and getWrappedClass, respectively.2> calls the populateBean method to populate the property, i.e@AutowireParse and inject < with set and GET methods3At this point, a bean object is almost created and its properties are almost populated.4> calls initializeBean to perform subsequent operations on the bean object, including calls to the InitializedBean interface methods and@PostContructorAnnotation parsing, and AOP, which is at the heart of our chapterCopy the code

InitializeBean method

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  // Call various xxxAwarexx interface methods
  invokeAwareMethods(beanName, bean);
  Object wrappedBean = bean;

  // Execute BeanPostProcessor's before method, which completes processing of the @postContructor annotation
  if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }// Call the afterPropertiesSet method of InitializingBean
  invokeInitMethods(beanName, wrappedBean, mbd);

  // A bean object has been created, the properties have been populated, the initialization method has been invoked, and the AOP proxy is executed
  if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}
Copy the code

Call AbstractAutoProxyCreator postProcessAfterInitialization method to complete the AOP

PostProcessAfterInitialization method
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  if(bean ! =null) {
    // Get the real beanName of the bean object
    Object cacheKey = getCacheKey(bean.getClass(), beanName);

    // Normally earlyProxyReferences is not included, only when a circular dependency is present
    // If a cyclic dependency occurs, the proxy will be done in advance, so it is no longer needed
    // Yes, I will
    if (!this.earlyProxyReferences.contains(cacheKey)) {
      returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code
wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // These three judgments are a continuation of the AOP initialization work above. When AOP initialization works, all the unnecessary ones will be screened out
  // Classes that participate in an AOP proxy, such as those annotated by the @Aspect annotation, will simply return beans at this point, thus no longer AOP
  if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    return bean;
  }
  if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
  }
  if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
  }

  // Start creating the AOP proxy, get the notification type, and call createProxy to complete the creation of the proxy object
  // Create proxy if we have advice.
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  if(specificInterceptors ! = DO_NOT_PROXY) {// If an object is included in an AOP advice, it is first added to the advisedBean with value true
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
    Object proxy = createProxy(
        bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }

  // If an object is not included in the AOP advice, it is added to the advisedBean with value false
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;
}
Copy the code
GetAdvicesAndAdvisorsForBean obtain all applicable to the current bean’s notice
protectedObject[] getAdvicesAndAdvisorsForBean( Class<? > beanClass, String beanName,@Nullable TargetSource targetSource) {

  List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  if (advisors.isEmpty()) {
    return DO_NOT_PROXY;
  }
  returnadvisors.toArray(); } analysis: use the findEligibleAdvisors method to find the appropriate notification. If it is found, convert it to an array and return it. If not, DO_NOT_PROXY is returnednull)

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); }returneligibleAdvisors; } analysis: As you can see, Spring calls the findCandidateAdvisors method, which was detailed earlier in the shouldSkip method describing AOP preparation, to find all the notifications and cache them, But calling this method at this point is taking it from the cache and calling findAdvisorsThatCanApply to find the advice that applies to the current class, extendAdvisors is an empty method that extends, and if it finds the right advice, sort it, Because the notification methods are then called sequentially, for example@Beforein@AfterBefore performingCopy the code
The findAdvisorsThatCanApply method finds the appropriate advice
Spring loops through all the notifications and does one thing for each notification. That is, it loops through all the methods of the current class to determine if the notification is satisfied. If so, it is an appropriate notification. In other words, there is a two-layer loop inside the method, with an outer loop for advice and an inner loop for methodsCopy the code
CreateProxy Creates a proxy object
/** * the main job of createProxy is to create a proxy factory. This proxy factory defines the rules for creating AOP objects, such as whether to enforce Cglib dynamic proxies, etc. Finally, getProxy of this factory object is called to createProxy objects */
protected Object createProxy(Class
        beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

  ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);

  if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
      proxyFactory.setProxyTargetClass(true);
    }
    else {
      evaluateProxyInterfaces(beanClass, proxyFactory);
    }
  }

  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  proxyFactory.addAdvisors(advisors);
  proxyFactory.setTargetSource(targetSource);
  customizeProxyFactory(proxyFactory);

  proxyFactory.setFrozen(this.freezeProxy);
  if (advisorsPreFiltered()) {
    proxyFactory.setPreFiltered(true);
  }

  returnproxyFactory.getProxy(getProxyClassLoader()); } analysis: In this method, Spring builds a proxy factory to create the proxy object. In the proxy factory, Spring puts all notifications into the factory. The appropriate notifications are put into the InvocationHandler called by the proxy object and stored as member variables. The JdkDynamicAopProxy object (which is an InvocationHandler) is created later, and in each of these objects, the notification for the original object is stored and a targtSource is set up in the proxy factory, This targetSource is passed in by createProxy and is a SingletonTargetSource created by Spring with an unproxied object as a parameter. This object is also stored in the InvocationHandler called by the proxy object. This is the JdkDynamicAopProxy created later so that the raw object can be retrieved via targetSource in the Invoke methodCopy the code
The getProxy method creates a proxy object
public Object getProxy(@Nullable ClassLoader classLoader) {
  return createAopProxy().getProxy(classLoader);
}

protected final synchronized AopProxy createAopProxy(a) {
  return getAopProxyFactory().createAopProxy(this);
}

public AopProxyFactory getAopProxyFactory(a) {
  return this.aopProxyFactory;
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  if(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<? > targetClass = config.getTargetClass();if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config);
  }
  else {
    return newJdkDynamicAopProxy(config); }} analysis: The createAopProxy method in getProxy captures the AOP proxy factory and creates the corresponding AOP proxy policy, which determines whether to use JDK dynamic proxies or Cglib dynamic proxies. Then call the getProxy method to create the Proxy object. For JDK dynamic proxies, this is proxy.newinstance. For Cglib, this is Enhancer. I won't go into the deep analysis hereCopy the code

conclusion

AOP source analysis is about the same, we from the AOP initialization to start some of the configuration, and then speak to AOP implementation that is really BeanPostProcessor postProcessAfterInitialization method, by choosing the agent strategy in the method, The wrapIfNecessary method is very important, as shown by the name, and wraps the bean if necessary. Therefore, in this method, it determines whether an object needs to be propped up. If you need a proxy, create a proxy object, this method needs to be paid attention to, because it is the key to understand the loop dependent second level cache!!Copy the code