编程知识 cdmana.com

3.2 spring source code series -- circular dependency source code analysis

First , We are 3.1 spring5 Source series -- Cyclic dependence And Handwritten code simulation spring Cyclic dependence   The implementation of the loop depends on handwriting . This implementation is simulated spring The cycle of dependence . The aim is to make it easier to understand spring Source code .

Now let's get down to business , have a look spring The loop depends on the source code .

 

One 、getBean Overall process

 

The goal is clear , Just to see spring How to solve the problem of circular dependence . 

The code entry is refresh()#finishBeanFactoryInitialization(beanFactory);

Two 、 Dismantle every step of the research process

Calling method beanFactory.preInstantiateSingletons(); Instantiate the remaining singletons bean. Why the rest ? Obviously, we've instantiated a part of it . For example, configuration class , postProcessor etc. .

2.1 entrance

 1 @Override
 2     public void preInstantiateSingletons() throws BeansException {
 3         if (logger.isTraceEnabled()) {
 4             logger.trace("Pre-instantiating singletons in " + this);
 5         }
 6 
 7 
 8         //  Get all... In the container bean The name of the definition 
 9         List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
10 
11 // Trigger initialization of all non-lazy singleton beans...
12 /**
13 *  First step :  loop bean Defined name
14 */
15 for (String beanName : beanNames) {
16 //  obtain bean Definition 
17 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
18 //  production bean The conditions of definition :  It's not abstract ,  Is a singleton ,  It's not lazy to load .  According to this standard ,  Finally, we call getBean() production bean
19 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
20 //  Here we judge whether it is a factory bean,  Here and BeanFactory It's not the same thing ,  Judge the current bean Is it implemented beanFactory The interface of 
21 if (isFactoryBean(beanName)) {
22 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
23 if (bean instanceof FactoryBean) {
24 final FactoryBean<?> factory = (FactoryBean<?>) bean;
25  boolean isEagerInit;
26 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
27 isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
28 ((SmartFactoryBean<?>) factory)::isEagerInit,
29  getAccessControlContext());
30  }
31 else {
32 isEagerInit = (factory instanceof SmartFactoryBean &&
33 ((SmartFactoryBean<?>) factory).isEagerInit());
34  }
35 if (isEagerInit) {
36 //  obtain bean
37  getBean(beanName);
38  }
39  }
40  }
41 else {
              // The second step : call bean Definition 42 getBean(beanName); 43 } 44 } 45 } 46 47 // Trigger post-initialization callback for all applicable beans... 48 /** 49 * loop bean Defined name 50 */ 51 for (String beanName : beanNames) { 52 // Get the instance from the cache instance 53 Object singletonInstance = getSingleton(beanName); 54 if (singletonInstance instanceof SmartInitializingSingleton) { 55 final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; 56 if (System.getSecurityManager() != null) { 57 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 58 smartSingleton.afterSingletonsInstantiated(); 59 return null; 60 }, getAccessControlContext()); 61 } 62 else { 63 smartSingleton.afterSingletonsInstantiated(); 64 } 65 } 66 } 67 }

First , loop bean Definition , It's simulated with us spring The first step in the loop is the same . 

The second step : Judge from BeanDefinitionMap This one from the bean Whether the production is satisfied bean Conditions

We pay attention to the code comments ,  production bean The conditions of definition :  It's not abstract , Is a singleton , It's not lazy to load . According to this standard , Finally, we call getBean() production bean

then : call getBean()

up to now , We have completed the first part of the source map above :

 

 

 2.2 establish bean Preparations before

So let's see getBean().doGetBean() Method

  1 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
  2             @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  3 
  4         //  First step :  transformation bean name.  Here comes in name It could be an alias ,  It could be a factory bean Of name,  So here's a conversion 
  5         final String beanName = transformedBeanName(name);
  6         Object bean;
  7 
  8         // Eagerly check singleton cache for manually registered singletons.
  9         //  The second step :  Try to get the object from the cache ,  If you don't get it, create it bean
 10         Object sharedInstance = getSingleton(beanName);
 11         if (sharedInstance != null && args == null) {
 12 if (logger.isTraceEnabled()) {
 13 // Determine whether the current class is being created 
 14 if (isSingletonCurrentlyInCreation(beanName)) {
 15 logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
 16 "' that is not fully initialized yet - a consequence of a circular reference");
 17  }
 18 else {
 19 logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
 20  }
 21  }
 22 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 23  }
 24 
 25 else {
 26 // Fail if we're already creating this bean instance:
 27 // We're assumably within a circular reference.
 28 /**
 29 *  Judge the current bean Is it more than one ,  If it's this that throws an exception 
 30 *
 31 *  Judge the current bean Is it more than one bean.  If the @Scope("prototype")  It means that this is a multi instance bean
 32 * spring  Can only solve the single object setter Cyclic dependency of Injection ,  Can't solve constructor Injection 
 33 *
 34 *  If it's multiple bean,  Currently creating bean,  Exceptions will also be thrown --- This is also a problem of circular dependence 
 35 */
 36 if (isPrototypeCurrentlyInCreation(beanName)) {
 37 throw new BeanCurrentlyInCreationException(beanName);
 38  }
 39 
 40 /**
 41 *  The following code is about the child parent container ,  Only spring mvc Inherited from spring,  There will be problems with child parent containers .
 42 */
 43 // Check if bean definition exists in this factory.
 44 BeanFactory parentBeanFactory = getParentBeanFactory();
 45 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 46 // Not found -> check parent.
 47 String nameToLookup = originalBeanName(name);
 48 if (parentBeanFactory instanceof AbstractBeanFactory) {
 49 return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 50  nameToLookup, requiredType, args, typeCheckOnly);
 51  }
 52 else if (args != null) {
 53 // Delegation to parent with explicit args.
 54 return (T) parentBeanFactory.getBean(nameToLookup, args);
 55  }
 56 else if (requiredType != null) {
 57 // No args -> delegate to standard getBean method.
 58 return parentBeanFactory.getBean(nameToLookup, requiredType);
 59  }
 60 else {
 61 return (T) parentBeanFactory.getBean(nameToLookup);
 62  }
 63  }
 64 
 65 /**
 66 *  Method parameter typeCheckOnly It's for judgment #getBean() When the method is used ,  Indicates whether to perform type checking only ,
 67 *  If it's not just type checking ,  It's about creating bean object ,  You need to call #markBeanAsCreated(String name)
 68 *
 69 */
 70 if (!typeCheckOnly) {
 71  markBeanAsCreated(beanName);
 72  }
 73 
 74 try {
 75 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 76  checkMergedBeanDefinition(mbd, beanName, args);
 77 
 78 // Guarantee initialization of beans that the current bean depends on.
 79 /**
 80 *  Now there are two bean1, bean2 ,  When loading, it calls bean1, bean2.  But if we want to bean2 Priority load ,  Just use @DependOn annotation 
 81 *  Used to parse with dependOn Annotated classes 
 82 */
 83 String[] dependsOn = mbd.getDependsOn();
 84 if (dependsOn != null) {
 85 for (String dep : dependsOn) {
 86 if (isDependent(beanName, dep)) {
 87 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 88 "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 89  }
 90  registerDependentBean(dep, beanName);
 91 try {
 92  getBean(dep);
 93  }
 94 catch (NoSuchBeanDefinitionException ex) {
 95 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 96 "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
 97  }
 98  }
 99  }
100 
101 // Create bean instance.
102 /**
103 *  The third step :  Create a single instance bean example 
104 */
105 if (mbd.isSingleton()) { //  Handle the singleton bean
106 /**
107 *  here getSingleton() And the above getSigleton Dissimilarity ,  The one above is taken from the first level cache .
108 *  This getSingleton() Just one thing :  take bean Set to the state being created .  This state is very important ,  If a cyclic dependency occurs ,  Find out bean Creating ,  There will be no more 
109 */
110 sharedInstance = getSingleton(beanName, () -> {
111 try {
112 return createBean(beanName, mbd, args);
113  }
114 catch (BeansException ex) {
115 // Explicitly remove instance from singleton cache: It might have been put there
116 // eagerly by the creation process, to allow for circular reference resolution.
117 // Also remove any beans that received a temporary reference to the bean.
118  destroySingleton(beanName);
119 throw ex;
120  }
121  });
122 //  obtain bean Instance object 
123 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
124  }
125 
126 else if (mbd.isPrototype()) { //  Deal with multiple cases bean
127 // It's a prototype -> create a new instance.
128 Object prototypeInstance = null;
129 try {
130 //  Currently creating multiple instances bean
131  beforePrototypeCreation(beanName);
132 //  Execution creation bean
133 prototypeInstance = createBean(beanName, mbd, args);
134  }
135 finally {
136  afterPrototypeCreation(beanName);
137  }
138 //  obtain bean Instance object 
139 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
140  }
141 
142 else { //  Deal with other types of bean
143 String scopeName = mbd.getScope();
144 final Scope scope = this.scopes.get(scopeName);
145 if (scope == null) {
146 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
147  }
148 try {
149 Object scopedInstance = scope.get(beanName, () -> {
150  beforePrototypeCreation(beanName);
151 try {
152 return createBean(beanName, mbd, args);
153  }
154 finally {
155  afterPrototypeCreation(beanName);
156  }
157  });
158 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
159  }
160 catch (IllegalStateException ex) {
161 throw new BeanCreationException(beanName,
162 "Scope '" + scopeName + "' is not active for the current thread; consider " +
163 "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
164  ex);
165  }
166  }
167  }
168 catch (BeansException ex) {
169  cleanupAfterBeanCreationFailure(beanName);
170 throw ex;
171  }
172 } 

 

ad locum , First get... From the cache bean, See if the cache already exists

 Object sharedInstance = getSingleton(beanName);

then , If the cache already exists , So long, just take it out . The code is as follows : 

    if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                // Judge the present bean Whether it's being created ( Single case bean)
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
 }
 }
 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 }

If it's empty , It's the first time to create , perform else Part of

First , Determine if it is a multiple instance being created bean, If it's multiple instances being created bean, Throw an exception ,

   It's already being created , That means it's at least the second time , Here we deal with the singleton bean The cycle of dependence , Don't deal with multiple cases bean The cycle of dependence , So throw an exception

   The corresponding code is this sentence

  

// Fail if we're already creating this bean instance:
 27             // We're assumably within a circular reference.
 28             /**
 29              *  Judge the current bean Is it more than one ,  If it's this that throws an exception 
 30              *
 31              *  Judge the current bean Is it more than one bean.  If the @Scope("prototype")  It means that this is a multi instance bean
 32              * spring  Can only solve the single object setter Cyclic dependency of Injection ,  Can't solve constructor Injection 
 33              *
 34              *  If it's multiple bean,  Currently creating bean,  Exceptions will also be thrown --- This is also a problem of circular dependence 
 35              */
 36             if (isPrototypeCurrentlyInCreation(beanName)) {
 37                 throw new BeanCurrentlyInCreationException(beanName);
 38             }

 

that , And then there's the first creation of bean. Created for the first time bean There are three situations :

   The first one is , This bean Is a singleton .

   The second kind , This bean Is more cases .

   The third kind of . Other types

The corresponding code is this piece of . With line number , You can match it one by one with the above

// Create bean instance.
102                 /**
103                  *  The third step :  Create a single instance bean example 
104                  */
105                 if (mbd.isSingleton()) { //  Handle the singleton bean
106                     /**
107                      *  here getSingleton() And the above getSigleton Dissimilarity ,  The one above is taken from the first level cache .
108                      *  This getSingleton() Just one thing :  take bean Set to the state being created .  This state is very important ,  If a cyclic dependency occurs ,  Find out bean Creating ,  There will be no more 
109                      */
110                     sharedInstance = getSingleton(beanName, () -> {
111                         try {
112                             return createBean(beanName, mbd, args);
113                         }
114                         catch (BeansException ex) {
115                             // Explicitly remove instance from singleton cache: It might have been put there
116                             // eagerly by the creation process, to allow for circular reference resolution.
117                             // Also remove any beans that received a temporary reference to the bean.
118 destroySingleton(beanName);
119 throw ex;
120 }
121 });
122 //  obtain bean Instance object 
123 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
124 }
125 
126 else if (mbd.isPrototype()) { //  Deal with multiple cases bean
127 // It's a prototype -> create a new instance.
128 Object prototypeInstance = null;
129 try {
130 //  Currently creating multiple instances bean
131 beforePrototypeCreation(beanName);
132 //  Execution creation bean
133 prototypeInstance = createBean(beanName, mbd, args);
134 }
135 finally {
136 afterPrototypeCreation(beanName);
137 }
138 //  obtain bean Instance object 
139 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
140 }
141 
142 else { //  Deal with other types of bean
143 String scopeName = mbd.getScope();
144 final Scope scope = this.scopes.get(scopeName);
145 if (scope == null) {
146 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
147 }
148 try {
149 Object scopedInstance = scope.get(beanName, () -> {
150 beforePrototypeCreation(beanName);
151 try {
152 return createBean(beanName, mbd, args);
153 }
154 finally {
155 afterPrototypeCreation(beanName);
156 }
157 });
158 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
159 }
160 catch (IllegalStateException ex) {
161 throw new BeanCreationException(beanName,
162 "Scope '" + scopeName + "' is not active for the current thread; consider " +
163 "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
164 ex);
165 }
166 }

Our focus is on a single case bean. therefore , Focus on the single example bean The implementation of the

105                 if (mbd.isSingleton()) { //  Handle the singleton bean
106                     /**
107                      *  here getSingleton() And the above getSigleton Dissimilarity ,  The one above is taken from the first level cache .
108                      *  This getSingleton() Just one thing :  take bean Set to the state being created .  This state is very important ,  If a cyclic dependency occurs ,  Find out bean Creating ,  There will be no more 
109                      */
110                     sharedInstance = getSingleton(beanName, () -> {
111                         try {
112                             return createBean(beanName, mbd, args);
113                         }
114                         catch (BeansException ex) {
115                             // Explicitly remove instance from singleton cache: It might have been put there
116                             // eagerly by the creation process, to allow for circular reference resolution.
117                             // Also remove any beans that received a temporary reference to the bean.
118                             destroySingleton(beanName);
119                             throw ex;
120                         }
121                     });
122                     //  obtain bean Instance object 
123                     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
124                 }

The point here is to call getSingleton(beanName, FactoryObject); FactoryObject It's an interface . A hook method is defined getObject(). 

This interface is defined here , They don't execute . When will it be implemented ? When called later . 

So let's see getSingleton() Method , The hook method is also called here .

 1 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
 2         Assert.notNull(beanName, "Bean name must not be null");
 3         synchronized (this.singletonObjects) {
 4             //  First step :  From the single level cache 
 5             Object singletonObject = this.singletonObjects.get(beanName);
 6             if (singletonObject == null) {
 7                 if (this.singletonsCurrentlyInDestruction) {
 8 throw new BeanCreationNotAllowedException(beanName,
 9 "Singleton bean creation not allowed while singletons of this factory are in destruction " +
10 "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
11  }
12 if (logger.isDebugEnabled()) {
13 logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
14  }
15 //  The second step :  take bean Add to singletonsCurrentlyInCreation in ,  Express bean Creating 
16  beforeSingletonCreation(beanName);
17 boolean newSingleton = false;
18 boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
19 if (recordSuppressedExceptions) {
20 this.suppressedExceptions = new LinkedHashSet<>();
21  }
22 try {
23 //  The third step :  This call getObject() Hook method ,  The anonymous function will be called back ,  call singletonFactory Of createBean()
24 singletonObject = singletonFactory.getObject();
25 newSingleton = true;
26  }
27 catch (IllegalStateException ex) {
28 // Has the singleton object implicitly appeared in the meantime ->
29 // if yes, proceed with it since the exception indicates that state.
30 singletonObject = this.singletonObjects.get(beanName);
31 if (singletonObject == null) {
32 throw ex;
33  }
34  }
35 catch (BeanCreationException ex) {
36 if (recordSuppressedExceptions) {
37 for (Exception suppressedException : this.suppressedExceptions) {
38  ex.addRelatedCause(suppressedException);
39  }
40  }
41 throw ex;
42  }
43 finally {
44 if (recordSuppressedExceptions) {
45 this.suppressedExceptions = null;
46  }
47  afterSingletonCreation(beanName);
48  }
49 if (newSingleton) {
50  addSingleton(beanName, singletonObject);
51  }
52  }
53 return singletonObject;
54  }
55 }

Here is the call getBean().

First step : Take the mature singleton from the first level cache bean. If you get , Go straight back . If you don't get . So do create . 

The second step : Before creation , Let's put this bean Put into the singleton you are creating bean Collection . Mark this bean It's being created

The third step : That is to call the hook method getObject() 了 . The method body of this method is defined above . Its content is to create instances

            sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //  Here we define a hook function .  It's just a definition ,  Not implemented .  In the real need to create bean Only in the place where 
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
 }
 });

The code logic here is the logic before creation

2.3 establish bean 

Let's look at creating bean The process of

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            /**
             *  First step :  Instantiation 
             *  The call chain is very deep ,  Look back 
             * bean There are two ways to instantiate 
             * 1.  Using reflection :   There are also two ways to use reflection ,
             *         a.  Through a parameterless constructor  ( Default method )
             *              from beanDefinition You can get beanClass,
             *             ClassName = BeanDefinition.beanClass
             *             Class clazz = Class.forName(ClassName);
             *             clazz.newInstance();
             *              So you can instantiate bean 了 
             *
             *         b.  By a parameter function .
             *            ClassName = BeanDefinition.beanClass
             *             Class clazz = Class.forName(ClassName);
             *             Constractor con = class.getConstractor(args....)
             *             con.newInstance();
             *
             * 2.  Use the factory 
             *          We use @Bean The way ,  It's the factory mode used ,  Control the instantiation process by yourself 
             *
             */
 instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 //  Here we use the decorator design pattern 
 final Object bean = instanceWrapper.getWrappedInstance();
 Class<?> beanType = instanceWrapper.getWrappedClass();
 if (beanType != NullBean.class) {
 mbd.resolvedTargetType = beanType;
 }

 // Allow post-processors to modify the merged bean definition.
 //  Allow post processor to modify merged beanDefinition
 synchronized (mbd.postProcessingLock) {
 if (!mbd.postProcessed) {
 try {
 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
 }
 catch (Throwable ex) {
 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 "Post-processing of merged bean definition failed", ex);
 }
 mbd.postProcessed = true;
 }
 }

 /**
 *  Cache singleton bean To level 3 cache ,  To prevent circular dependence 
 *  Judge whether it is early quoted bean,  If it is ,  It is allowed to expose references in advance 
     * * Conditions for judging whether you can get up early or not * 1. It's a singleton * 2. Allow circular dependency * 3. Creating bean */ boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // Pack our early objects into a singletonFactory object , The object provides getObject() Method , Put static bean Put it in Level 3 cache . addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { // The second step : Fill properties , Assign a value to a property ( call set Method ) This is also the post processor of the call populateBean(beanName, mbd, instanceWrapper); // The third step : initialization . exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } /** * After initialization , Judge whether it is an early object * It's circular dependence . To come in here */ if (earlySingletonExposure) { // Get our objects in the cache Due to the allowEarlyReference yes false, Request can only be fetched from level 1 and level 2 cache // Normal, ordinary bean( There is no circular dependence bean) During creation , Will not promote level 3 cache to level 2 Cache . Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }

First , Instantiation bean, There are two ways to instantiate . One is through reflection , The other is through dynamic proxy

/**
             *  First step :  Instantiation 
             *  The call chain is very deep ,  Look back 
             * bean There are two ways to instantiate 
             * 1.  Using reflection :   There are also two ways to use reflection ,
             *         a.  Through a parameterless constructor  ( Default method )
             *              from beanDefinition You can get beanClass,
             *             ClassName = BeanDefinition.beanClass
             *             Class clazz = Class.forName(ClassName);
             *             clazz.newInstance();
             *              So you can instantiate bean 了 
             *
             *         b.  By a parameter function .
             *            ClassName = BeanDefinition.beanClass
             *             Class clazz = Class.forName(ClassName);
             *             Constractor con = class.getConstractor(args....)
             *             con.newInstance();
             *
             * 2.  Use the factory 
             *          We use @Bean The way ,  It's the factory mode used ,  Control the instantiation process by yourself 
             *
             */
            instanceWrapper = createBeanInstance(beanName, mbd, args);

 

Judge whether it is early exposure bean. Meet early exposure bean The three conditions of

1. Is a singleton

2. Allow circular dependency

3. bean Is already in the creation of the line .

        /*  Conditions for judging whether you can get up early or not 
         *     1.  It's a singleton 
         *     2.  Allow circular dependency 
         *     3.  Creating bean
         */
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));    

establish bean The second step : Attribute assignment

//  The second step : Fill properties ,  Assign a value to a property ( call set Method )   This is also the post processor of the call 
populateBean(beanName, mbd, instanceWrapper);

It will be judged here that , With or without @Autowired Properties of . There are two kinds of them Name, One is Type

@SuppressWarnings("deprecation")  // for postProcessPropertyValues
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
 // Skip property population phase for null instance.
 return;
 }
 }

 // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
 // state of the bean before properties are set. This can be used, for example,
 // to support styles of field injection.
 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
 for (BeanPostProcessor bp : getBeanPostProcessors()) {
 if (bp instanceof InstantiationAwareBeanPostProcessor) {
 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
 return;
 }
 }
 }
 }

 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

 //  Determine whether the attribute has Autowired annotation 
 int resolvedAutowireMode = mbd.getResolvedAutowireMode();
 // Autowired By name or by type 
 if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
 MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
 // Add property values based on autowire by name if applicable.
 if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
 autowireByName(beanName, mbd, bw, newPvs);
 }
 // Add property values based on autowire by type if applicable.
 if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
 autowireByType(beanName, mbd, bw, newPvs);
 }
 pvs = newPvs;
 }

 ......
 }

If you inject... By name

  protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

        String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        for (String propertyName : propertyNames) {
            if (containsBean(propertyName)) {
                //  call getBean
                Object bean = getBean(propertyName);
                pvs.add(propertyName, bean);
                registerDependentBean(propertyName, beanName);
                if (logger.isTraceEnabled()) {
 logger.trace("Added autowiring by name from bean name '" + beanName +
 "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
 }
 }
 else {
 if (logger.isTraceEnabled()) {
 logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
 "' by name: no matching bean found");
 }
 }
 }
 }

Will call... Again getBean Method . structure bean. This is the possibility of circular dependence . 

Injection by type is the same . 

Just parsing bean In different ways .

 

establish bean The third step of : initialization

 //  The third step :  initialization .
 exposedObject = initializeBean(beanName, exposedObject, mbd);

Initializing bean When , Will call a lot of aware. It also calls init-method Method . as well as bean Post processor for .

 

Step four : Delete the data of instantiation and static methods in cache

     /**
         *  After initialization ,  Judge whether it is an early object 
         *  It's circular dependence .  To come in here 
          */
        if (earlySingletonExposure) {
            //  Get our objects in the cache   Due to the allowEarlyReference yes false,  Request can only be fetched from level 1 and level 2 cache 
            //  Normal, ordinary bean( There is no circular dependence bean)  During creation ,  Will not promote level 3 cache to level 2 Cache .
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
 String[] dependentBeans = getDependentBeans(beanName);
 Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
 for (String dependentBean : dependentBeans) {
 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
 actualDependentBeans.add(dependentBean);
 }
 }
 if (!actualDependentBeans.isEmpty()) {
 throw new BeanCurrentlyInCreationException(beanName,
 "Bean with name '" + beanName + "' has been injected into other beans [" +
 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
 "] in its raw version as part of a circular reference, but has eventually been " +
 "wrapped. This means that said other beans do not use the final version of the " +
 "bean. This is often the result of over-eager type matching - consider using " +
 "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
 }
 }
 }
 }
removeSingletonIfCreatedForTypeCheckOnly Calling method ,  Delete cache .

This is both getBean() The whole process . There are many details in the middle , I didn't look into it , because spring The code is very deep , If we look too deep, we forget our goal . Combined with the previous handwritten spring From the perspective of circular dependence , It's still understandable . 

 

 

3、 ... and . Then there are a few questions

problem 1: Why you need L2 and L3 caches ?

The second level cache is used to store the early bean, That is, it is not assigned and initialized by the property bean
The main function of level 3 cache is to decouple . After decoupling, it is called asynchronously , The hook method is stored in the third level cache , It's an interface . Call when using bean Post processor for

 

problem 2: Have you solved the circular dependency of constructors

The answer is no . Because constructors are built at the time of instantiation . This is the time bean They haven't been created yet , So there's no way to deal with circular dependencies . If there is a circular dependency of the constructor , It's a direct mistake ..

 

problem 3: Have you solved the cyclic dependency in multiple cases

There is no such thing , Because we judge , If it's more than one , Then an exception will be thrown

 1             /**
 2              *  The second step :  Judge the present bean Whether it's a multiple instance being created bean,  If so, throw an exception 
 3              *
 4              * 2.  Judge the current bean Is it more than one bean.  If the @Scope("prototype")  It means that this is a multi instance bean
 5              * spring  Can only solve the single object setter Cyclic dependency of Injection ,  Can't solve constructor Injection 
 6              *
 7              *  If it's multiple bean,  Currently creating bean,  Exceptions will also be thrown --- This is also a problem of circular dependence 
 8              */
 9             if (isPrototypeCurrentlyInCreation(beanName)) {
10                 throw new BeanCurrentlyInCreationException(beanName);
11             }          

 

版权声明
本文为[The sun in full bloom]所创,转载请带上原文链接,感谢

Scroll to Top