The core function of Spring is the container function, which is used to store beans. Here are a few concepts that need to be clear: what is a container and what is a bean? Beans can be understood as class instance objects in the system, and containers are BeanFactory implementation classes in Spring.
1. Define the Spring container first
We have two ways to configure Spring containers, one is xml configuration, and the other is java configuration (usually combined)
// 1. xml configuration initialization container ApplicationContext applicationContext = new ClassPathXmlApplicationContext("config/beanFactoryTest.xml"); // 2. java configuration initialization container ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
Why is the container ApplicationContext instead of the BeanFactory we mentioned above? Here we need to explain the difference between ApplicationContext and BeanFactory.
BeanFactory: The factory interface of beans provides the basic method of obtaining beans. The interface relationship of BeanFactory is as follows:
Application Context: Application context, inherited from BeanFactory and other interfaces, has its own extended functions such as Environment Capable and Message Source (commonly used)
In the previous example, we used ClassPathXml Application Context and Annotation Config Application Context. In the following analysis, we use Annotation Config Application Context as an example to illustrate:
/** * Create a new AnnotationConfigApplicationContext, deriving bean definitions * from the given annotated classes and automatically refreshing the context. * @param annotatedClasses one or more annotated classes, * e.g. {@link Configuration @Configuration} classes */ public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { /* 1. The first step is to call the default constructor to create two tool objects * Annotation bean s define readers * this.reader = new AnnotatedBeanDefinitionReader(this); * Class path bean definition scanner * this.scanner = new ClassPathBeanDefinitionScanner(this); */ this(); // 2. Registration Profile register(annotatedClasses); // 3. Refresh containers refresh(); }
The first step is to create a reader and scanner for us, the second step is to register the configuration file, and the last step is not the most important step to refresh the container.
The first step is not to analyze, the second step is to simply analyze the registration profile: this step is actually to call the reader we created in the first step to analyze all the annotation information of the configuration file, and then register the annotation information definition object in our registry (the registry is Annotation Config Application Context).
public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); } <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { // Get all the annotation information for the configuration file AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); ..................... ................................ // Register Annotation Configuration Information in our Application Context BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
The third step, refresh(), is also the core step: in this step, all the construction of Spring containers and bean s is completed, which is subdivided into the following steps
// 1. Pretreatment - > Pretreatment before refresh prepareRefresh(); // 2. Pretreatment - > Getting bean Factory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. Pretreatment - > Bean Factory Pretreatment before Use prepareBeanFactory(beanFactory); // 4. Preprocessing - - > bean factory post-processor (left to subclass implementation) postProcessBeanFactory(beanFactory); // 5. Execute the post-processor of the post-BeanFactory invokeBeanFactoryPostProcessors(beanFactory); // 6. Registered Bean Post Processor registerBeanPostProcessors(beanFactory); // 7. Initialization of message components initMessageSource(); // 8. Initialize application event dispatcher initApplicationEventMulticaster(); // 9. Initialize other components (left to subclass extensions) onRefresh(); // 10. Registered listeners registerListeners(); // 11. Instantiate all other non-lazy bean s finishBeanFactoryInitialization(beanFactory); // 12. Publish Container Creation Completion Event finishRefresh();
1. prepareRefresh()
The first step is the preparation before refreshing. It mainly completes the environmental state setting of the container.
protected void prepareRefresh() { // Set Start Date to Close Active Status this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); // Initialize attribute resources initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, //Creating Early Event Containers this.earlyApplicationEvents = new LinkedHashSet<>(); }
2. obtainFreshBeanFactory()
In this step, we created the BeanFactory factory. Follow up the source code and get the factory by calling the obtainFreshBeanFactory of AbstractApplicationContext, where refreshBeanFactory() and getBeanFactory() are both interface methods, which are really implemented in its interface implementation class, such as the ApplicationContext interface above. Relation presentation, annotation configuration is implemented in Generic Application Context, and Xml configuration is implemented in AbstractRefreshable Application Context abstract class
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
Whichever implementation class is, eventually an instance of DefaultListableBeanFactory is created as a container Bean factory
/** * Create a new GenericApplicationContext. * @see #registerBeanDefinition * @see #refresh */ // 1. Create factory instances public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } // 2. Setting Serialized ID for Container Factory @Override protected final void refreshBeanFactory() throws IllegalStateException { if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } this.beanFactory.setSerializationId(getId()); }
3. prepareBeanFactory()
Pre-processing of the newly created Bean Factory is mainly to complete the post-processor and parser addition of beans and the configuration of the automatic assembly interface.
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 1. Setting class loader and expression parser beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 2. Setting up bean post-processor beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 3. Setting Ignore Automatic Assembly Interface beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // 4. Register Automated Assembly Components beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 5. Add bean postprocessor beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); ................................ }
4. postProcessBeanFactory()
Manage the post-processor (add, delete....) before executing the call to BeanFactory's post-processor, leaving it to the subclass extension function.
5. invokeBeanFactoryPostProcessors()
Execute the BeanFactoryPostProcessor method by delegating it to the PostProcessor RegistrationDelegate class to execute:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 1. Delegate to the PostProcessorRegistrationDelegate class for execution PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); }
True call implementation: There are many source codes to implement, so here's a summary:
The first step is to execute the BeanFactoryPostProcessor method, which is manually added to the container through the addBeanFactoryPostProcessor method, to determine whether its type is a sub-type BeanDefinition RegistryPostProcessor, and if it is a sub-type, to execute the method specific to the sub-class interface first, and then to execute the BeanFactoryPostProcessor interface method:
//1. Prioritize interfaces first and then execute subinterface-specific methods invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //2. Execute the BeanFactoryPostProcessor interface method invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
Step 2: If we place the post-processor in the container through the @Component annotation, we get all the processor definitions by the method first.
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
Then instantiate the processor through getBean()
beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)
Finally, method calls are made after the processors are sorted:
sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
So we can see that the post-processor for Step 5 Bean Factory execution was executed before all beans were instantiated.
6. initMessageSource()
Initialize message components for internationalization, message binding, message parsing
// Use empty MessageSource to be able to accept getMessage calls. DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; // Registered Single Instance Message Component beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
7. initApplicationEventMulticaster()
Initialize the application event broadcast dispatcher for subsequent event Publishing
// 1. Instantiate a simple application broadcast event dispatcher this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); // 2. Register it as a single instance in BeanFactory beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
8. onRefresh()
Initialize other special components and leave them to subclass extension implementations
9. registerListeners()
Register listeners in the event dispatcher in step 7
protected void registerListeners() { // Register statically specified listeners first. // 1. Register instantiated listeners with dispatchers for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // uninitialized to let post-processors apply to them! // 2. Get the annotated listener and complete the instantiation registration String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... // 3. Publish events in an earlier event container Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
10.finishBeanFactoryInitialization()
This step is to complete the initialization of other beans and is also the core step of container refresh. Let's analyze what it did when the beans were initialized.
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ........................ // Instantiate all remaining (non-lazy-init) singletons. // Initialize the singleton bean object beanFactory.preInstantiateSingletons(); }
Continue to follow up on preInstantiate Singletons (it is an interface method for Configurable Listable BeanFactory, which is implemented by default as DefaultListable BeanFactory, the default factory class we created above)
@Override public void preInstantiateSingletons() throws BeansException { List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... // 1. Create a single instance bean that is not lazy to load for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 2. Determine whether a factory bean is available if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> 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 { // Focus: Creating bean s getBean(beanName); } } }
In fact, the method of creating beans is getBean(beanName) method. Let's follow it up and finally enter the doGetBean() method of AbstractBeanFactory. There are many codes in doGetBean() and the most important thing is to say:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 1. Mark that the bean has been created markBeanAsCreated(beanName); // 2. Get all dependent beans for beans String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { //Throw an exception if a cyclic dependency occurs if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // Register Dependent Beans registerDependentBean(dep, beanName); try { //Recursively create bean instances getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 3. Determine whether a singleton bean is available if (mbd.isSingleton()){ // Focus on creating bean s return createBean(beanName, mbd, args); } // 4. Determine whether prototype bean s are available or not ......................................................... }
From the source code above, we can easily find that the instantiation of bean s is created in createBean(). Continue to follow in and find a solid interface method of AbstarctBeanFactory, which is implemented by the createBean() method in AbstractAutowire Capable BeanFactory.
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException { // 1. Check bean definition information .................................... // 2. Emphasis: Give BeanPostProcessor an opportunity to execute before the bean is instantiated Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // 3. bean instantiation Object beanInstance = doCreateBean(beanName, mbdToUse, args); return beanInstance; }
From the above source code, we can see that before bean instantiation, there will be a BeanPostProcessor post-processor execution opportunity. The execution time of different implementations of BeanPostProcessor is different in the whole system initialization process. First, we will analyze which bean resolveBeforeInstantiation() is to execute before bean instantiation. Post-processing:
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) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; } @Nullable protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
By analyzing the source code, we can see that the post-processor of beans executed before the initialization of beans must implement the post-processor of the InstantiationAwreBeanPostProcessors interface. This processor is actually used to help us generate proxy objects in AOP. We will explain it later in AOP source code analysis. It's OK to have a concept at home, but the reader needs to know which methods are invoked here for the InstantiationAwreBeanPostProcessors interface. The InstantiationAwreBeanPostProcessors interface inherits from the BeanPostProcessor interface and extends four interface methods: pre-initialization and initialization of BeforeInstantiation to its parent class interface. In resolve, the first thing to call is its own instantiated pre-processor, and if there is a return result, the initialization post-processor is called.
// 1. Bean pre-instantiation processing @Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } // 2. Bean instantiation post-processing default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } // 3. Processing before the factory uses attributes @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { return null; } // 4. Abandoned @Deprecated @Nullable default PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { return pvs; }
If resolveBeforeInstantation returns the proxy object directly, otherwise continue to call the doCreateBean method to create the bean instance.
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) { // Create instances and wrap bean s through BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); } }
doCreateBean creates bean instances and wraps BeanWrapper by calling createBeanInstance. Specifically, how to create beans to continue to follow up the instantiateBean() method is not explained here. After the instantiation of beans is completed, populateBean() is called to fill in the bean attributes:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // 1. First, execute the instantiated post processor that implements the InstantiationAwreBeanPostProcessors interface if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } // 2. Perform Successful Continue to Execute Attribute Application Postprocessor pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); // 3. Filling attributes applyPropertyValues(beanName, mbd, bw, pvs); }
After the beans'attributes are filled, initializeBean() is called to initialize the beans. The aware method is executed before the real initialization method is invoked, then the Bean initialization preprocessor is executed, and the post processor is executed after initialization.
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { // 1. Execute the method of realizing Aware interface if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; // 2. Initialize the Preprocessor by calling Bean if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 3. Initialization method call invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } // 4. Initialization Post Processor Called if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
This completes the initial creation of the container, finishBeanFactoryInitialization.
11. finishRefresh()
The last step is to refresh the container. In this step, it is important to clean up the cache, publish events and so on.
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
Finally, the entire container initialization process is completed.