After parsing the configuration, how is the bean loaded
preface
Since Spring has worked so hard to register the bean, we need to take it out and use it. Before we use it, we need to go through one more step: loading the bean.
As mentioned in the first note, donebean
Registered tobeanDefinitionMap
After the registry, a number of post-handler methods are called, including onefinishBeanFactoryInitialization()
“The notes readInstantiate all remaining (non-lazy-init) singletons
, meaning that non-lazy-loaded classes will be instantiated in this step to complete the class loading.
And we usecontext.getBean("beanName")
Method, if corresponding tobean
Non-lazy-loaded, so you can just pull it out and use it, lazy-loadedbean
You need the above steps to load the class, after the load can be used ~
Let’s take a look at how the bean is loaded in these two steps.
Sequence diagram
Our code analysis is all around this method, please position yourself well in advance:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
The amount of code being loaded by this bean is a bit too much, over 100 lines, so I’ve organized the sequence diagram to get a clear overview of the loading process:
This sequence diagram shows the general flow of bean loading, but there are many details that are not shown in the diagram. Let’s take a look at the overall process first, and then follow along with the code.
The code analysis
Note: due to the amount of code, each post a large section of code looks more difficult, so I show the key code, download the project to see the complete notes, with the source code analysis ~
Code cloud Gitee address
Making the address
The use of the FactoryBean
Before looking at the loading process, there is a pre-concept to understand that in general, Spring instantiates a bean using its class attribute to specify the implementation class through reflection.
Quotes from books:
In some cases, instantiating beans can be complicated. For example, in the case of multiple parameters, the traditional method requires a lot of configuration information in the configuration file, which is not flexible. In this case, you can use the FactoryBean interface provided by Spring, which users can implement to customize the logic of instantiating beans.
The FactoryBean interface defines three methods:
public interface FactoryBean<T> { T getObject() throws Exception; Class<? > getObjectType(); default booleanisSingleton() {
return true; }}Copy the code
Let’s talk about usage:
When the
class implementation class in the configuration file is a FactoryBean, the getBean() method returns not the FactoryBean itself, but the object returned by the FactoryBean#getObject() method.
Use the demo code below:
After extending FactoryBean, you need to override the two methods in the diagram to return the types through the generic convention. In overloaded methods, do your own personalized processing.
GetBean (“beanName”). The difference is whether beanName uses the & prefix. If there is no & prefix, It recognizes the car type returned by FactoryBean. GetObject, which, if prefixed with &, will return a class of type FactoryBean.
Verify and learn the concepts in the book, the fastest way is to run a sample code, see whether the output results meet expectations, so reference the examples in the book, their own hand to play the code, see the final output results, found consistent with the book, but also deepen the rightFactoryBean
Understanding.
Why firstBeanFactory
What about this concept?
From the sequence diagram, at step 1.5, the method is called:
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
And in this step, you’re going to judgesharedInstance
Type, if belongs toFactoryBean
, will invoke user customizationFactoryBean
的 getObject()
methodsbean
Initialization.
The actual type of instantiation isgetObjectType()
The type defined by the method, notFactoryBean
The original type. What is finally registered in the container isgetObject()
The returnedbean
.
I gave you this idea in advance, but hopefully you won’t be confused by this at the end.
Get the singleton bean from the cache
// Eagerly check singleton cache for manually registered singletons.
// Check if the corresponding instance exists in the cache or in the instance factory or is retrieved from the ObjectFactory in singletonFactories
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
// Check if there is an instance in the cache
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// Remember that all public variables need to be locked to avoid concurrent modification by multiple threads
synchronized (this.singletonObjects) {
// No processing if the bean is being loaded
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// When some methods need to be pre-initialized, calling the addSingletonFactory method will be the corresponding
// objectFactory initialization policies are stored in singletonFactoriesObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
if(singletonFactory ! =null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName); }}}}return singletonObject;
}
Copy the code
The singleton pattern is often used in code design. In Spring, singletons of the same container are created only once, and beans are fetched directly from the singleton cache singletonObjects.
And because the singleton cache is a public variable, so when it is operated, it is locked, avoiding the overwriting operation of concurrent modification or reading by multiple threads.
There is also an earlySingletonObjects variable, which is also a singleton cache, and is also used to hold the relationship between beanName and the created bean instance.
withsingletonFactories
The difference is when a singletonbean
It’s put in hereearly
After the singleton is cached, the cache is obtained fromsingletonFactories
, the two are mutually exclusive, mainly used to solve the problem of loop dependency. (More on loop dependency in the next article)
Get the object from the instance of the bean
In the getBean method, getObjectForBeanInstance is a high frequency method. It can be used to get beans in the singleton cache or load beans according to different scope policies. So let’s see what this method does.
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
// Return the corresponding instance, sometimes there are cases such as BeanFactory that do not return the instance itself directly
// Instead returns the instance returned by the specified method
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
Copy the code
Specific method implementation, search for comments 4.6 look at the code comments:
Describe the process of this method:
- validation
bean
type: Check whether it is a factorybean
- For the
FactoryBean
Don’t do processing - right
bean
convert - To deal with
FactoryBean
type: entrusted togetObjectFromFactoryBean
Method to process.
In this method, the FactoryBean is treated in the same way as the FactoryBean method mentioned above, and the result is the type returned by the factorybean.getobject () method.
For the fourth step, delegating to the getObjectFromFactoryBean method won’t go into detail, but there are three methods worth mentioning:
// Singleton operation, front operation
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// Singleton mode, after operation
afterSingletonCreation(beanName);
}
Copy the code
Code in the class load, there are pre – and post-operations, before the first note, many of the pre – and post-operations are empty methods, such as user-defined extensions.
However, this is not an empty method. The two methods are used to save and remove the state of the class load, and are used to detect cyclic dependencies.
At the same time, these two methods are also used when loading beans in different scopes, which is also a high-frequency method.
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
Copy the code
This is a post-processing method, and I don’t know much about it, but let me write down the concept:
A clause in the Spring for the bean’s rules: as far as possible, ensure that all will be called after the bean initialization register BeanPostProcessor postProcessAfterInitialization method for processing. In real development, you can extend this feature.
Access to the singleton
Now go to step 1.3 in the sequence diagram:
// Create bean instance
// singleton singleton (most commonly used)
if (mbd.isSingleton()) {
/ / the second parameter of the callback interface, the interface is org. Springframework. Beans. Factory. ObjectFactory# getObject
// createBean(beanName, MBD, args)
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
// omit try/catch
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
Copy the code
Let’s see what the getSingleton method does:
public Object getSingleton(String beanName, ObjectFactory
singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// Comment 4.7 Global variables, lock
synchronized (this.singletonObjects) {
// Check to see if the bean is already loaded
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// Check whether the beanName is initialized by another thread and add it to the initialization state
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
// Initializes the bean, which is what the callback interface just called, and actually executes the createBean method
singletonObject = singletonFactory.getObject();
newSingleton = true;
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// Remove the initialization state after initialization
afterSingletonCreation(beanName);
if (newSingleton) {
// add cacheaddSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code
To sort out the process:
- Check whether the cache has been loaded
- No loading, record
beanName
Load state of - Invoke the callback interface to instantiate
bean
- Handling method calls after loading singletons: This step is to remove the load state
- Log the result to the cache and delete the load
bean
The various auxiliary states recorded during the process
Step 2 and Step 4, as mentioned earlier, are used to record the loading status of the bean and are used to detect cyclic dependencies, which will be skipped here.
The key method is the third step, which calls the getObject() method of the ObjectFactory. The actual callback interface implements the createBean() method, which needs to be explored below.
Ready to createbean
For the book, there is a saying that is very accurate:
In Spring the source code, the function is actually a real working do at the beginning of, such as doGetBean, doGEtObjectFromFactoryBean, and entry functions, such as getObjectFromFactoryBean, In fact, from the overall point of view to do overall planning work.
Once you have this concept in mind, look at the Spring source code later, and you will know this routine. Learn the overall flow in the entry function, and then focus on the work method starting with do.
Following this pattern, let’s look at the entry methodcreateBean()
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
RootBeanDefinition mbdToUse = mbd;
Make sure that the bean class has been parsed at this point, and clone the bean definition in case the dynamically parsed class cannot be stored in the shared merge bean definition.
// Lock the class and resolve the class according to the class property or according to the classNameClass<? > resolvedClass = resolveBeanClass(mbd, beanName);if(resolvedClass ! =null&&! mbd.hasBeanClass() && mbd.getBeanClassName() ! =null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// Verify and prepare the override method
mbdToUse.prepareMethodOverrides();
// Give beanPostProcessor the opportunity to return the proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if(bean ! =null) {
// Short circuit operation, if the agent successfully created the bean, directly return
return bean;
}
/ / create a bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
Copy the code
To summarize the process:
- The class is resolved according to the class property set or according to className
- Methods for validating and preparing coverageThis method is used to handle two configurations: we recognize the default tags when we parse them
lookup-method
和replaced-method
Property, and the loading of the two configurations will be stored togetherbeanDefinition
In themethodOverrides
In the properties. - The pre-initialization post-handler is applied to resolve whether the specified bean has a pre-initialization short-circuit operation
- Create a bean
Here are the main steps
Handling the Override attribute
public void prepareMethodOverrides(a) throws BeanDefinitionValidationException {
// Check that lookup methods exists.
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
// Handle the Override attributeprepareMethodOverride(mo); }}}}Copy the code
As you can see, get the list of overloaded methods of the class and iterate through them, one by one. Specifically, the properties are lookup-method and replace-method. The configurations resolved in this step will be stored in the methodOverrides property of beanDefinition to prepare for instantiation later.
If the methodOverrides attribute is detected during the bean’s instantiation, it dynamically generates a proxy for the current bean and uses the corresponding interceptor to enhance the bean.
(I don’t recommend using this approach in business code, because it’s a hassle to locate the problem and call it, and you can get it wrong =-=)
Pre-processing before instantiation
// Give beanPostProcessor the opportunity to return the proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if(bean ! =null) {
// Short circuit operation, if the agent successfully created the bean, directly return
return bean;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
// Perform the pre-interceptor operation
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if(bean ! =null) {
// Execute the operation of the back interceptorbean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
}
return bean;
}
Copy the code
Before the doCreateBean method, there is a short circuit that, if the post-handler succeeds, returns the bean for the broker.
In resolveBeforeInstantiation approach, in ensuring that bean information has already been parsing is complete, perform the two key methods, see from the comments, one is the front of the interceptor operations, the other is the rear of the interceptor operations.
If the first pre-interceptor is successfully instantiated, the singleton bean is already in the cache. It doesn’t go through the normal bean creation process and doesn’t get a chance to make post-processor calls, so in the second step here, After the application is for the sake of the bean can processor postProcessAfterInitialization method.
Create a bean
Finally, the key method of doing the work: doGetBean. There is no specific pre-processing after the validation of the previous method, so it is a normal bean, which is created in the doGetBean method.
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// Comment 4.8 Create new instances based on the specified bean using the corresponding strategy such as follow up method look, there are factory methods, constructor auto-injection, simple initialization
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
finalObject bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }// Allows the post-handler to modify the merged bean definition
synchronized (mbd.postProcessingLock) {
if(! mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed =true; }}// Whether the exposure needs to be advanced, which is used to solve the cycle dependence
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// The second argument is the callback interface, which implements the function of dynamically weaving facets into the bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
// Populate the bean to inject individual attribute values
// If there are dependencies on other beans, the dependent bean is initialized recursively
populateBean(beanName, mbd, instanceWrapper);
// Call an initialization method, such as init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
// earlySingletonReference is not null only if a cyclic dependency is detected
if(earlySingletonReference ! =null) {
if (exposedObject == bean) {
// If exposedObject is not changed in the initialization method, it is not enhanced
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// Check dependencies
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// After a bean is created, the bean it depends on must already be created
If actualDependentBeans are not empty, the dependentBeans have been found above
// Indicates that there are dependent beans that have not been initialized, i.e. there are cyclic dependencies
if(! actualDependentBeans.isEmpty()) {throw newBeanCurrentlyInCreationException(beanName); }}}// Register bean as disposable.
// Register the bean according to scope
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
Copy the code
It’s a bit dizzying to see such a long code, so let’s go through the flow of this method:
- If the loaded bean is a singleton, clear the cache
- Instantiate the bean to convert BeanDifinition into BeanWrapper
- The post-processor modifies the definition of the merged bean: The processing of the bean after the merge. Autowired annotations formalize this method for things like pre-parsing of types
- Depend on the processing
- Property population: Populates all properties into the instance of the bean
- Cyclic dependency check
- Register DisposableBean: This step is used to dispose of the destroy-method property, which is registered in this step to be called when the object is destroyed.
- Complete the creation and return.
As can be seen from the above process, this method does a lot of things, so that the code is more than 100 lines, giving people a poor reading experience, so try to split the small method, as simple as possible in the entrance method, explain what to do, specific in the small method to complete.
Because the code of this creation process is a lot and complex, I choose the key point to understand and learn, and the details need to be further studied:
Create an instance of the bean
In the second step above, you instantiate the bean and return the BeanWrapper
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.Class<? > beanClass = resolveBeanClass(mbd, beanName); Supplier<? > instanceSupplier = mbd.getInstanceSupplier();// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// If a class has multiple constructors, each of which takes a different parameter, you need to check the corresponding constructor or factory method before calling it
if(mbd.resolvedConstructorOrFactoryMethod ! =null) {
resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; }}}// If already parsed, do not need to parse again
if (resolved) {
if (autowireNecessary) {
/ / the actual parsing is org. Springframework. Beans. Factory. Support. ConstructorResolver. AutowireConstructor
// The constructor is automatically injected (=-=)
return autowireConstructor(beanName, mbd, null.null);
}
else {
// Use the default constructor
returninstantiateBean(beanName, mbd); }}// Candidate constructors for autowiring? The constructor needs to be parsed based on the parametersConstructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if(ctors ! =null) {
// constructor injection
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor. No special handling, the default constructor is used
return instantiateBean(beanName, mbd);
}
Copy the code
Brief introduction of functions:
- The factory method is used for initialization if one exists
- A class has multiple constructors, each of which takes different parameters, so the bean needs to be instantiated based on the parameter locking constructorIn this step, I am truly convinced that I put a lot of effort into matching the specific constructor. If you are interested, you can locate this function to watch
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
- If neither a factory method nor a constructor with parameters exists, the bean is instantiated using the default constructor
In this process, the bean instance is generated using either the factory method or the constructor, which is the configuration from the RootBeanDefinition passed in
I’m not going to track it down, let’s go to the next step
Handling loop dependencies
// Whether the exposure needs to be advanced, which is used to solve the cycle dependence
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// The second argument is the callback interface, which implements the function of dynamically weaving facets into the bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Copy the code
The key method is addSingletonFactory, which adds the ObjectFactory that created the instance to the singleton factory before the bean is initialized
As you saw from the beginning, ObjectFactory is the factory that you use to create objects. When the object is instantiated, it will determine whether the dependent object has been created by checking whether the ObjectFactory of the dependent object is in the singleton cache. If not, it will create the dependent object first, and then put the ObjectFactory into the singleton cache.
If there is a cyclic dependency, it needs to be exposed in advance so that the dependent party can find and instantiate it normally.
Circular dependency solutions will be covered in more detail in the next article.
Properties into
This is also a high frequency method. The property is injected during initialization, and some code snippets are posted:
populateBean(beanName, mbd, instanceWrapper);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// Give the awareBeanPostProcessor one last chance to modify the bean's properties before setting them
boolean continueWithPropertyPopulation = true;
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { ...if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation =false;
break; }... } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() :null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
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) {
// Automatically inject by name
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// Automatic injection by type
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// The post-processor has been initialized
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Dependency check is required
booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds =null;
// Fetch the BeanPostProcessor result set from the beanPostProcessors object and iterate through the postprocessors
for (BeanPostProcessor bp : getBeanPostProcessors()) {
...
}
// Also used for dependency checking
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
// Apply the attributes to the bean, using a deep copy, copying the attributes of the subclass
applyPropertyValues(beanName, mbd, bw, pvs);
}
Copy the code
Because the code is too long, if you are interested, go to comment 4.11
Introduce the processing process:
- call
InstantiationAwareBeanPostProcessor
The processorpostProcessAfterInstantiation
Method to determine whether the controller continues with the property population - Depending on the injection type (
byName/byType
), extract dependentbean
, unified depositPropertyValues
中 - Determine whether to proceed
BeanPostProcessor
And dependency checks:
- Postprocessors, if available, will be applied
InstantiationAwareBeanPostProcessor
The processorpostProcessProperties
Method, the property is processed again before the property is acquired and populated. - use
checkDependencies
Method to perform dependency checking
- All parsed to
PropertyValues
Property in theBeanWrapper
In the.
In this method, properties are populated based on different injection types, processed by the post-call handler, and finally applied tobean
In the.
I won’t go into details here, but let’s move on to the next method
Initialize the bean
In the configuration file, when the
tag is used, the init-method property is used for this purpose: before the bean is instantiated, the method specified by init-method is called to instantiate the bean according to the user’s business. Let’s look at the entry method initializeBean:
// Call an initialization method, such as init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// Comment 4.12 securityManage =-=
if(System.getSecurityManager() ! =null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// If there is no securityManage, the method validates the bean type and needs to reference the Aware interface
// Handle special beans: Aware/ BeanClassLoader/BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null| |! mbd.isSynthetic()) {// Familiar with that, post-processor again
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// Activate the user-defined init-method method
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}
Copy the code
This method is mainly used to call the initialization method we set up, but inside the method, there are other operations, so let’s talk about the flow:
1. Activate the Aware method
Spring provides some Aware interfaces. Beans that implement this interface, after being initialized, can obtain corresponding resources, such as BeanFactoryAware. After initialization, Spring container will inject an instance of BeanFactory. So if you need to get these resources, refer to the Aware interface.
2. Post-execution processor
We can customize, modify, and extend postprocessors like PostProcessor. BeanPostProcessor class postProcessBeforeInitialization and postProcessAfterInitialization, for example, can to the logical extension of before and after the bean loading, You can think of it as the idea of faceted AOP.
3. Enable the custom init method
The obvious purpose of this method is to find the user-defined constructor and call it. Note that if the bean is of type InitializingBean, the afterPropertiesSet method is called.
The execution sequence is firstafterPropertiesSet
, followed byinit-method
Defined methods.
Registered disposableBean
This is an extension entry to Spring’s destruction methods, and Spring’s dad has reserved all the options we can consider and want to extend. In addition to destroy destroy method – the method attribute configuration, also can register the post-processor DestructionAwareBeanPostProcessor to unified handling bean destroy method:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { AccessControlContext acc = (System.getSecurityManager() ! =null ? getAccessControlContext() : null);
if(! mbd.isPrototype() && requiresDestruction(bean, mbd)) {if (mbd.isSingleton()) {
// Singleton mode
/ / register DisposableBean
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
scope.registerDestructionCallback(beanName,
newDisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); }}}Copy the code
So here you’re registering to disposableBean at different scopes.
conclusion
This note summarizes the class loading process, combining sequence diagrams and code analysis to gain a deeper understanding of it.
At the same time, I also have some feelings about code writing:
- Don’t write long methods, try to break them into small methods, clear intention
From the very beginning when I looked at Spring source code, I was amazed by the cleanliness and logical clarity of the code. The entry method shows what needs to be done, and then works on the specific logical breakdown, which shows the masterful design of the code designer.
So when I saw that there were several methods with more than 100 lines, I made a little joke in my heart. It seems that I also have something in common with the code written by the big guys, that is, it can be optimized
- Log in all key places to facilitate troubleshooting and location
Due to the length of the code fragments, some logical judgment and log processing have been removed, but log management is a very important part. Printing logs in key places, troubleshooting problems and analyzing data will help.
If you are too lazy to print logs, do not print logs in key places, even if there is a problem, do not know where to start, the cause of the problem can not be exposed, resulting in user complaints, it is not worth the loss.
Due to limited personal skills, if there is any misunderstanding or mistake, please leave a comment, and I will correct it according to my friends’ suggestions
Spring-analysis-note cloud Gitee address
Spring – analysis – note making address
The resources
-
Spring Core Container source code analysis three: Spring Beans initialization process analysis
-
— Beijing: Posts and Telecommunications Press
Portal:
-
Spring source learning – environment preparation
-
(1) The infrastructure of the container
-
Spring source code learning (2) default tag parsing
-
Spring source code learning (3) custom tags
-
Spring source code learning (four) bean loading
-
Spring source code learning (5) loop dependency
-
Spring source code learning (six) extension function part 1
-
Spring source code learning (seven) extension features part 2
-
Spring source learning (eight) AOP use and implementation principle
-
Spring source code learning (9) Transaction Transaction
-
(10) Spring MVC