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

The sun in full bloom 2020-11-11 06:33:06
spring source code series circular


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]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云