This is the 27th day of my participation in the August Genwen Challenge.More challenges in August
preface
Finish the initialization of this context’s bean factory, Instantiate all remaining (non-lazy-init) singletons.
This method mainly does the creation and initialization of ordinary beans. This method instantiates all remaining non-lazy-loaded singleton beans.
Spring source code analysis series
- Spring source code analysis – source code reading environment construction
- Spring source Code analysis -IOC basic concepts
- Spring source code analysis -IOC core components
- Spring Source Code Analysis -IOC source code Analysis (1)
- Spring IOC source code analysis -obtainFreshBeanFactory
- Spring IOC source analysis – invokeBeanFactoryPostProcessors (3)
- The Spring IOC source analysis – registerBeanPostProcessors (4)
Let’s review the 12 steps of Refresh
Source code analysis
1. finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 1. Initialize the context transformation service
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
// 2. If beanFactory did not register the embedded value parser before, register the default embedded value parser: mainly used for annotation attribute value parsing.
if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 3. Initialize the loadTimeWeaverBean instance object
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// 4. Freeze all bean definitions as bean instance objects are about to be created
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 5. Instantiate all remaining (non-lazy-loaded) singletons
beanFactory.preInstantiateSingletons();
}
Copy the code
2. preInstantiateSingletons
@Override
public void preInstantiateSingletons(a) throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 1. Create copies of beanDefinitionNames beanNames for subsequent traversals to allow methods such as init to register new bean definitions
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 2. Iterate over beanNames to trigger initialization of all non-lazy-loaded singleton beans
for (String beanName : beanNames) {
// 3. Get the MergedBeanDefinition of beanName
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 4. Bd corresponds to the Bean instance: not abstract class && is a singleton && is not lazy loading
if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {// 5. Check whether the bean corresponding to beanName is a FactoryBean
if (isFactoryBean(beanName)) {
// 5.1 Obtain a FactoryBean instance from beanName
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceofFactoryBean) { FactoryBean<? > factory = (FactoryBean<? >) bean;// 5.2 Determine if this FactoryBean wants to be initialized eagerly
boolean isEagerInit;
if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if (isEagerInit) {
// 5.3 If you want eager initialization, get the bean instance via beanNamegetBean(beanName); }}}else {
// 6. If the bean corresponding to beanName is not a FactoryBean, but a plain bean, get the bean instance by beanNamegetBean(beanName); }}}// Trigger post-initialization callback for all applicable beans...
/ / 7. Traverse beanNames, trigger all SmartInitializingSingleton after initialization callback
for (String beanName : beanNames) {
// 7.1 Obtaining the bean instance corresponding to beanName
Object singletonInstance = getSingleton(beanName);
/ / 7.2 whether singletonInstance SmartInitializingSingleton interface is realized
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
/ / 7.3 triggered SmartInitializingSingleton afterSingletonsInstantiated method implementation class
if(System.getSecurityManager() ! =null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else{ smartSingleton.afterSingletonsInstantiated(); }}}}Copy the code
3. getMergedLocalBeanDefinition
MergedBeanDefinition MergedBean definitions are called merged Bean definitions because there is a parent-child relationship.
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// Check whether the cache is available
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if(mbd ! =null && !mbd.stale) {
return mbd;
}
// Get MergedBeanDefinition based on beanName and beanName
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
Copy the code
4. getMergedBeanDefinition
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
/ / 1. The chains
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
// 2. Check whether the MergedBeanDefinition corresponding to beanName exists in the cache
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 3. If the MergedBeanDefinition corresponding to beanName does not exist in the cache
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
// 4. If the parentName of BD is empty, it indicates that BD has no parent definition, and there is no need to merge with the parent definition
if (bd instanceof RootBeanDefinition) {
// 4.1 If bd is of type RootBeanDefinition, clone a copy directly
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
Otherwise, build a RootBeanDefinition
mbd = newRootBeanDefinition(bd); }}else {
// Child bean definition: needs to be merged with parent.
// 5. Otherwise, bd has a parent definition and needs to be merged with the parent definition
BeanDefinition pbd;
try {
// 5.1 Get the beanName defined by the parent
String parentBeanName = transformedBeanName(bd.getParentName());
// 5.2 If the beanName defined by the parent is different from that of the bean
if(! beanName.equals(parentBeanName)) {// 5.3 Recursively obtain the MergedBeanDefinition of the parent
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
If the beanName defined by the parent is the same as the beanName defined by the BD, then the parent BeanFactory,
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
// 5.5 If the parent BeanFactory is ConfigurableBeanFactory, the MergedBeanDefinition defined by the parent BeanFactory is obtained
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
// 5.6 If no, throw an exception directly
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent"); }}}catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
// 5.7 Build a new RootBeanDefinition object with parent PBD (deep copy)
mbd = new RootBeanDefinition(pbd);
// 5.8 Override the parent definition with bd
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
// 6. If scope is not configured, set to default singleton
if(! StringUtils.hasLength(mbd.getScope())) { mbd.setScope(SCOPE_SINGLETON); }// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
If containingBd is not empty &&mbD is singleton
// Set MDB's scope to containingBd's scope
if(containingBd ! =null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
// 8. Put beanName and MBD into the mergedBeanDefinitions cache for direct use later
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd); }}if(previous ! =null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
// return MergedBeanDefinition
returnmbd; }}Copy the code
5. transformedBeanName
Resolving name to a true beanName involves removing the ampersand prefix from the FactoryBean and resolving the alias.
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
/ / beanName transformation
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if(! name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// Resolve the alias to a real beanName
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if(resolvedName ! =null) { canonicalName = resolvedName; }}while(resolvedName ! =null);
return canonicalName;
}
Copy the code
The difference between FactoryBean and BeanFactory
BeanFactory is the Bean factory, the parent of the ApplicationContext, and the core of the IOC container, responsible for producing and managing Bean objects. A FactoryBean is a Bean, and you can implement the FactoryBean interface to customize the logic of instantiating the Bean, by proxying a Bean object, and doing things before and after a method.
6. getMergedBeanDefinition
The parent container BeanFactory
There may be multiple BeanFactories in Spring, which may have a “parent factory” and “child factory” relationship.
The most common examples are:
Spring MVC’s BeanFactory and Spring MVC’s BeanFactory. Usually, Spring’s BeanFactory is the “parent factory” and Spring MVC’s BeanFactory is the “child factory”. In Spring, a child factory can use the BeanDefinition of the parent factory, so if it is not found in the current BeanFactory and the parent factory exists, it will look in the parent factory.
@Override
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
//1. Get the real beanName (parse alias)
String beanName = transformedBeanName(name);
// Efficiently check whether bean definition exists in this factory.
// If the BeanFactory is not ConfigurableBeanFactory, the BeanFactory is ConfigurableBeanFactory.
if(! containsBeanDefinition(beanName) && getParentBeanFactory()instanceof ConfigurableBeanFactory) {
// Call the parent BeanFactory to get the MergedBeanDefinition of beanName
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
}
// Resolve merged bean definition locally.
// 3. Parse beanName's MergedBeanDefinition in the current BeanFactory
return getMergedLocalBeanDefinition(beanName);
}
Copy the code
7. isFactoryBean
@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
// 1. Get the real beanName (remove & prefix, parse alias)
String beanName = transformedBeanName(name);
// 2. Try to fetch the Bean instance object from the cache
Object beanInstance = getSingleton(beanName, false);
if(beanInstance ! =null) {
// 3. If beanInstance exists, the type is FactoryBean
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if(! containsBeanDefinition(beanName) && getParentBeanFactory()instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
// 5. The parent beanFactory is ConfigurableBeanFactory if the beanName && does not exist in the cache
// The parent BeanFactory is called to determine if it is a FactoryBean
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
// 6. Check whether beanName is a FactoryBean by using MergedBeanDefinition
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
Copy the code
8. getSingleton
Classic level 3 cache code, common interview questions how to solve the cycle dependency? Why level 3 cache, is level 2 cache ok and so on?
Spring has a three-level cache internally
- SingletonObjects level 1 cache, used to hold instantiated, injected, and initialized bean instances
- EarlySingletonObjects A secondary cache used to hold instantiated bean instances
- The singletonFactories level 3 cache is used to hold bean creation factories so that later extensions have a chance to create proxy objects.
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 1. Obtain the singleton corresponding to beanName from the singleton cache
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 2. If there is no singleton in the cache and the corresponding singleton bean for the beanName is being created
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. Lock to perform operations
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// 4. Fetch a singleton from the earlier singleton cache (level 1 cache)
EarlySingletonObjects were called early singletons because the objects in earlySingletonObjects were created by the pre-exposed ObjectFactory without property padding
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
Get beanName's singleton factory from the singleton factory cacheObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
if(singletonFactory ! =null) {
// 7. If there is a singleton factory, create a singleton from the factory
singletonObject = singletonFactory.getObject();
// 8. Place the singleton created by the singleton factory into the early singleton cache
this.earlySingletonObjects.put(beanName, singletonObject);
// 9. Remove the beanName singleton factory because the singleton factory has already created an instance object and placed it in the earlySingletonObjects cache.
// Therefore, the subsequent beanName singleton can be retrieved from the earlySingletonObjects cache without the need to use the singleton factory
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
Copy the code
9. isFactoryBean
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Boolean result = mbd.isFactoryBean;
if (result == null) {
// 1. Obtain the type of the Bean instance corresponding to beanNameClass<? > beanType = predictBeanType(beanName, mbd, FactoryBean.class);// 2. Returns whether beanType is FactoryBean itself, a subclass, or a subinterfaceresult = (beanType ! =null && FactoryBean.class.isAssignableFrom(beanType));
mbd.isFactoryBean = result;
}
return result;
}
Copy the code
10. predictBeanType
@Nullable
protectedClass<? > predictBeanType(String beanName, RootBeanDefinition mbd, Class<? >... typesToMatch) { Class<? > targetType = mbd.getTargetType();if(targetType ! =null) {
return targetType;
}
if(mbd.getFactoryMethodName() ! =null) {
return null;
}
return resolveBeanClass(mbd, beanName, typesToMatch);
}
Copy the code
The last
Review the finishBeanFactoryInitialization the main function of common Bean creation and initialization. There are also some very confusing concepts
- MergedBeanDefinition merger BeanDefinition
- The difference between FactoryBean and BeanFactory
- The parent container BeanFactory
- Spring inside a three-level cache, singletonObjects earlySingletonObjects, singletonFactories