Spring is a familiar framework for any Java developer, but if you really want to understand its implementation and how it works, you need to analyze and think about the Spring source code.
Download the source code
Source download view visible: view spring source
Understand the Spring container to refresh the logical, namely to explore AbstractApplicationContext# refresh () method were done. This method is the core of Spring Bean loading and defines the entire Spring context loading process.
In this article, we’ll examine the refresh logic of the entire Spring container in terms of the various methods in Refresh.
The refresh method
- PreareRefresh Preparation for work before refresh
- ObtainFreshBeanFactory gets the refreshed internal beanFactory instance of the subclass
- PrepareBeanFactory registers the necessary system-level beans for the container
- PostProcessBeanFactory allows container subclasses to de-register postProcessor
- InvokeBeanFactoryPostProcessors call container container level registered post processor
- RegisterBeanPostProcessors registered Bean with the container level post processor
- InitMessageSource Initializes internationalization configuration
- InitApplicationEventMulticaster initialization event publishers components
- OnRefresh is reserved for subclasses to initialize other special beans before the singleton Bean is initialized
- RegisterListeners Register event listeners with the previous event publisher component
- FinishBeanFactoryInitialization set the system level of service, instantiate all the lazy loading singleton
- FinishRefresh triggers the callback method when the initialization is complete and publishes the event when the container refresh is complete to the listener
- ResetCommonCaches resets the common cache in the Spring kernel
Ok, let’s examine the refresh method
@Override
public void refresh(a) throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for the refresh. Update of status values
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. This section analyzes only the creation of a beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Register some system beans required by the container, such as classLoader, etc
prepareBeanFactory(beanFactory);
try {
// Allow subclasses of the container to register postProcessor, hook methods
postProcessBeanFactory(beanFactory);
/ / activate the registration for bean BeanFactoryPostProcessors in the container
// Scan all beanDefinitions in the application and register them in the container
invokeBeanFactoryPostProcessors(beanFactory);
// Register the BeanPostProcessor that intercepts bean creation
registerBeanPostProcessors(beanFactory);
// Provide a message source for ApplicationContext
initMessageSource();
/ / initialize ApplicationEventMulticaster such as event publishers,
// We can store all event listeners and notify different event listeners based on different events.
initApplicationEventMulticaster();
/ / reserved for AbstractApplicationContext subclass is used to initialize other special bean,
// This method needs to be called before all singleton beans are initialized
// For example, the Web container initializes ThemeSource related beans.
onRefresh();
// Register listeners (check listener beans and register them)
registerListeners();
// Set a custom type converter ConversionService,
// Set custom AOP-related class LoadTimeWeaverAware,
// Clear the temporary ClassLoader
// Instantiate all classes (except lazily loaded classes)
finishBeanFactoryInitialization(beanFactory);
/ / initializes the container to the life cycle of the event handler, (the default use DefaultLifecycleProcessor), call extends SmartLifecycle the start method of the interface
// After the Spring container has loaded all the beans and initialized them, it then calls back the corresponding method (the start method) in the class that implements the interface.
ContextRefreshedEvent to the event listener after refreshing the event with the release container
finishRefresh();
}
// ··· catch }}Copy the code
The refresh method
PreareRefresh Work preparation before refresh
Container preparation: Record the start time startupDate of the Spring container, mark the container as active, initialize the context such as file path information, and verify whether required properties are filled.
protected void prepareRefresh(a) {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
// 1. Set the status of the container to active
this.active.set(true);
/ /... logger
// 2. Initialize the Environment propertySources property
initPropertySources();
// 3. Verify that all Environment requiredProperties exist
/ / please refer ConfigurablePropertyResolver# setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
// 4. Create an event set
this.earlyApplicationEvents = new LinkedHashSet<>();
}
Copy the code
ObtainFreshBeanFactory obtains the internal beanFactory instance after subclass refresh
Get into the bean tag in the XML configuration of various attributes, encapsulated into a BeanDefinition object, then the object to our beanDefinitionMap, beanDefinitionNames IOC container, For use in the IOC container and create conditions to obtain the ConfigurableListableBeanFactory is created.
This method is carefully analyzed in “Spring source analysis (2) BeanFactory creation and XML configuration parsing”.
PrepareBeanFactory registers the necessary system-level beans for the container
As you can see, after the beanFactory is created, the code continues to register some system beans needed in the container, such as classLoader, and so on.
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Set beanFactory to use the container's classloader
beanFactory.setBeanClassLoader(getClassLoader());
// Set beanFactory's expression language handler
// Spring3 began to add support for language expressions. The default is to use the form #{bean.xxx} to call the related property values
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// Add a default propertyEditor for beanFactory
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Add the function of this handler: inject ApplicationContext objects when application-defined beans implement the ApplicationContextAware interface
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// If a bean depends on the implementation classes of the following interfaces, ignore them when autowiring.
// Spring handles these dependencies in other ways.
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// Fix the dependencies, where you register some special rules for autoluing, such as the implementation class of the BeanFactory interface, and specify the current BeanFactory at runtime
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register an early post-processor that detects internal beans as application listeners
/ / ApplicationListenerDetector role is to determine whether a particular Bean ApplicationListener,
// If so, join the event listener queue.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// If you find a LoadTimeWeaver, you are ready to add the back-end processor to the beanFactory
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set temporary class loaders for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register the default environment
if(! beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); }if(! beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); }if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
Copy the code
PostProcessBeanFactory allows container subclasses to deregister postProcessor
Spring then allows container subclasses to de-register postProcessor, which Spring reserves for subclasses to implement.
Five, the invokeBeanFactoryPostProcessors call container container level registered post processor
In invokeBeanFactoryPostProcessors method, we gave PostProcessorRegistrationDelegate concrete implementation logic agent to handle, This is basically a class that aggregates the call logic of the registered PostProcessor into one class. Let’s follow this up:
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
beanFactoryPostProcessors)
{
/ / if there is one BeanDefinitionRegistryPostProcessor priority
Set<String> processedBeans = new HashSet<>();
// If BeanDefinitionRegistry type is present
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// To record the regular BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
/ / BeanDefinitionRegistryPostProcessor is recorded
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// Iterates through all the BeanFactoryPostProcessors passed in (they are not registered in the container as beans)
// Divide the BeanFactoryPostProcessor passed in with all parameters into two groups:
/ / BeanDefinitionRegistryPostProcessor and conventional spring BeanFactoryPostProcessor
/ / 1. If is BeanDefinitionRegistryPostProcessor now perform postProcessBeanDefinitionRegistry (),
// 2. Otherwise, the record will be a normal BeanFactoryPostProcessor and no processing will be performed
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else{ regularPostProcessors.add(postProcessor); }}/ / used to record the current BeanDefinitionRegistryPostProcessor was about to be executed
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
/ / first of all, to implement the interface priority order form of Bean BeanDefinitionRegistryPostProcessor make calls
/ / register find all containers for BeanDefinitionRegistryPostProcessor postProcessor name array
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
for (String ppName : postProcessorNames) {
/ / traversal container, rear BeanDefinitionRegistryPostProcessor type of processor Bean instance to add to the current register in the processor
if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); }}// Order by priority
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
/ / execute sequentially BeanDefinitionRegistryPostProcessors
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
/ / the second interface to realize the Ordered BeanDefinitionRegistryPostProcessors invoked
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// Order by Order
sortPostProcessors(currentRegistryProcessors, beanFactory);
// Make the fully ordered BeanDefinitionRegistry
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
/ / in the end, the remaining BeanDefinitionRegistryPostProcessors execution
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
for (String ppName : postProcessorNames) {
if(! processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate =true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
/ / because BeanDefinitionRegistryPostProcessor inherited from spring BeanFactoryPostProcessor, so here
/ / for all BeanDefinitionRegistryPostProcessor also call its methods postProcessBeanFactory ()
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// Call the method postProcessBeanFactory() on all regular BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// If both are regular BeanFactoryPostProcessor, call its method postProcessBeanFactory()
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
/ / the above logic performed in the form of parameters of the incoming BeanDefinitionRegistryPostProcessor and common spring BeanFactoryPostProcessor
/ / BeanDefinitionRegistryPostProcessor also carried out inside the container, so the container left spring BeanFactoryPostProcessor need to deal with
// The logic is the same, which can be PriorityOrdered, Ordered, or neither
/ /...
}
Copy the code
Learn more about full link resolution in the annotated article series
Six, registerBeanPostProcessors registered Bean with the container level post processor
To allow container subclasses to deregister postProcessor, the hook method facilitates processing of the postProcessor when the getBean method is called to create bean instances
InitMessageSource Initializes internationalization configuration
Some internationalization-related configurations, if not defined in this context, use the parent context’s internationalized resources.
protected void initMessageSource(a) {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// The parent context's MessageSource is known using this context's MessageSource.
if (this.parent ! =null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// If no parent MessageSource has been registered, only the parent context is set to the parent MessageSource
// registered already.hms.setParentMessageSource(getInternalParentMessageSource()); }}if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]"); }}else {
// Use an empty MessageSource to accept calls to the getMessage method
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); }}}Copy the code
Eight, initApplicationEventMulticaster initialization event publishers components
Initialize ApplicationEventMulticaster such as event publishers can store all event listeners information, and according to the different events, notice different event listeners
protected void initApplicationEventMulticaster(a) {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/ / if the container is ApplicationEventMulticaster bean instance,
/ / applicationEventMulticaster is assigned to the containers
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); }}else {
/ / not create a new SimpleApplicationEventMulticaster,
/ / and completed the SimpleApplicationEventMulticaster Bean registration
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); }}}Copy the code
OnRefresh is reserved for subclasses to initialize other special beans before the singleton Bean is initialized
Template method, which can be overridden to add context-specific refresh work. For example: StaticWebApplicationContext# onRefresh () to initialize the theme USES The method in a particular instance instantiation (finishBeanFactoryInitialization) before call special bean initialization.
RegisterListeners Register event listeners with the previous event publisher component
Add the application listener as the listener bean. If it doesn’t affect other listeners, you can add them without beans.
protected void registerListeners(a) {
// First register the static listener specified
for(ApplicationListener<? > listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); }// Don't initialize FactoryBean here. We need to keep all the normal beans (event listeners) uninitialized.
// Let the post processor apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true.false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
/ / at this point, has completed the listeners registered to ApplicationEventMulticaster,
// Now we finally have a multiplexer to publish previous application events to listeners.
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if(earlyEventsToProcess ! =null) {
for(ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); }}}Copy the code
11, finishBeanFactoryInitialization setting system level service, instantiate all the lazy loading singleton
Complete the initialization of the beanFactory for this context, initializing all remaining singleton beans.
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize the converter for this container
// It is the responsibility of the converter to handle the type conversion when assigning values to bean instance member variables by configuration
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));
}
// If the bean postProcessor is not registered, the default parser is registered
/ / (for example, is mainly used to parse the properties file is accomplished)
// @value annotation or use ${} in XML to configure the environment
if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// AOP is divided into three types: compile-time weaving, classload-time weaving, and run-time weaving
// LoadTimeWeaving is the second type, which is used for weaving through the JVM
// Initialize LoadTimeWeaverAware beans to register their transformers as early as possible
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using temporary class loaders for type matching.
beanFactory.setTempClassLoader(null);
// Freeze the configuration to allow caching of all bean definition metadata with no further changes expected
beanFactory.freezeConfiguration();
// Instantiate all remaining singletons (non-lazy-init)
beanFactory.preInstantiateSingletons();
}
Copy the code
FinishRefresh triggers the callback method when the initialization is complete and publishes the event that the container refresh is complete to the listener
After the Spring container loads all the beans and completes the initialization, it then calls back to the corresponding method (the start() method) in the class that implements the interface and publishes the container flush finished event ContextRefreshedEvent to the corresponding event listener
protected void finishRefresh(a) {
// Clear the context-level cache of resources (such as scanned ASM metadata)
clearResourceCaches();
// Initialize the lifecycle handler for this context
initLifecycleProcessor();
// First propagate the refresh to the lifecycle processor
getLifecycleProcessor().onRefresh();
// Publish the final event
publishEvent(new ContextRefreshedEvent(this));
// If it is active, it participates in the LiveBeansView MBean.
LiveBeansView.registerApplicationContext(this);
}
Copy the code
ResetCommonCaches resets the common cache in the Spring kernel
Reset Spring common reflection metadata caching, especially ReflectionUtils AnnotationUtils, ResolvableType and CachedIntrospectionResults cache.
protected void resetCommonCaches(a) {
ReflectionUtils.clearCache();
AnnotationUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
Copy the code
conclusion
In summary, the Spring container to refresh the logic mainly in AbstractApplicationContext# refresh () method, this method is brief to empty the beanFactory as the initial state, and then according to the intention of the application to fill all kinds of bean instance.
This article is based on the spring framework 5.2.10.RELEASE version for analysis