Instantiation of Bean _01
In Spring Bean instantiation is a complex process, and starting from this article, I will learn container to initialize the refresh () method of inishBeanFactoryInitialization (the beanFactory);
FinishBeanFactoryInitialization () method code implementation
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
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 bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. 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. / * ** Freeze all bean definitions, indicating that the registered bean definition will not be modified or any further processing* / beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. / * ** Here is the key code* Initialize the remaining instances (non-lazy)* The completion of this preinstantiation is delegated to the container. If preinstantiation is required, use getBean() to trigger dependency injection.* Only the time and place are different from normal di firing, where DI occurs after the container executes refresh(), the IOC container initialization process* Normal dependency injection that is not lazy-init occurs when getBean() is first executed to the IOC container after initialization.* / beanFactory.preInstantiateSingletons(); } Copy the code
Of the above methods, the most important is preInstantiateSingletons(). My own interpretation here is to pre-instantiate the container’s non-lazy-init object.
preInstantiateSingletons()
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. // Get the names of all BeanDefinitions List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... // Trigger instantiation of all non-lazy-loaded singleton beans for (String beanName : beanNames) { // Merge parent BeanDefinition RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); / * ** An object is not abstract, is singleton, and is not lazily loaded* If the object is not a FactoryBean, go to the getBean() method* / if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) { if (isFactoryBean(beanName)) { // If it is a FactoryBean, add & Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { finalFactoryBean<? > factory = (FactoryBean<? >) bean; boolean isEagerInit; if(System.getSecurityManager() ! =null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { / * ** Call the getBean() method in the container* / getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if(System.getSecurityManager() ! =null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } } Copy the code
From the above method, we can see that all the Beannames added to the container at the beginning of the container are looped through, and then the corresponding BeanDefinition is obtained according to the BeanName. The properties in the BeanDefinition are used to determine whether to trigger the corresponding getBean() procedure. The first thing I need to do before getBean() is to try to draw a rough flowchart. Later articles will go through the sub-processes in the flowchart one by one.
Now that you’ve seen the entire flowchart, it’s time to start processing the logic for the first method getSingleton(String beanName)
getSingleton(String beanName)
public Object getSingleton(String beanName) {
/** the true argument sets the flag to allow early dependencies
return getSingleton(beanName, true);
}
Copy the code
Call the overloaded method getSingleton(String beanName, Boolean allowEarlyReference) to do the real logic. Early dependencies are allowed by default in Spring, AllowEarlyReference is true.
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Get the Bean from the Map, return it if it is not empty, no initialization is done
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// Uninitialized and beanName exists in the pool of the singleton Bean being created
synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { / * ** Called when some method needs to be pre-initializedThe addSingletonFactory method initializes the corresponding ObjectFactory policy* Stored in singletonFactories* / ObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName); if(singletonFactory ! =null) { /** Calls the pre-set getObject() method */ singletonObject = singletonFactory.getObject(); / * ** Record in the cache* earlySingletonObjects and singletonFactories are mutually exclusive* / this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; } Copy the code
When creating a Bean, first go to singletonObjects, which is a Map that holds the created object. The objects inside can be used directly. To illustrate the process of getSingleton() above, use the following image:
For the getSingleton() method, there must be no objects in singletonObjects when the container is initialized, and the return result must be NULL.
Three maps for the first time
In the above three methods, we will see three maps that are useful as follows; private final Map
singletonObjects = new ConcurrentHashMap<>(256); , private final Map
> singletonFactories = new HashMap<>(16); , private final Map
earlySingletonObjects = new HashMap<>(16); These three maps play an important role in the subsequent dependency injection processing. SingletonObjects is used to store fully initialized beans. SingletonFactories is used to store bean factory objects; EarlySingletonObjects holds the original bean object. There are three maps defined in Spring that cache beans instantiated in the Spring container and solve the problem of circular dependencies during injection.
The tag Bean is already created
protected void markBeanAsCreated(String beanName) {
// Not created
if (!this.alreadyCreated.contains(beanName)) {
Synchronized ensures that only one thread is created
synchronized (this.mergedBeanDefinitions) {
// Check again that there is no creation if (!this.alreadyCreated.contains(beanName)) { // Delete beanName from mergedBeanDefinitions, // And recreate it the next time you access it clearMergedBeanDefinition(beanName); // Add to the created bean collection this.alreadyCreated.add(beanName); } } } } Copy the code
Where the container is initialized, the beanName corresponding to our own Bean is not necessarily present in alreadyCreated. Thus, Spring here adds the current BeanName to the alreadyCreated collection to mark the current Bean as created. Here, in order to ensure that the add once, also adopted the way of double detection.
This article is formatted using MDNICE