目录
- 背景
- 探索-源码
- 进一步思考
背景
SpringBoot bean 加载顺序如何查看,想看加载了哪些bean, 这些bean的加载顺序是什么?
实际加载顺序不受控制,但会有一些大的原则:
1、按照字母顺序加载(同一文件夹下按照字母数序;不同文件夹下,先按照文件夹命名的字母顺序加载)
2、不同的bean声明方式不同的加载时机,顺序总结:@ComponentScan > @Import > @Bean
这里的ComponentScan指@ComponentScan及其子注解,Bean指的是@configuration + @bean
同时需要注意的是:
(1)Component及其子注解申明的bean是按照字母顺序加载的
(2)@configuration + @bean是按照定义的顺序依次加载的
(3)@import的顺序,就是bean的加载顺序
(4)在xml中,通过<bean id="">方式声明的bean也是按照代码的编写顺序依次加载的
(5)同一类中加载顺序:Constructor >> @Autowired >> @PostConstruct >> @Bean
(6)同一类中加载顺序:静态变量 / 静态代码块 >> 构造代码块 >> 构造方法(需要特别注意的是静态代码块的执行并不是优先所有的bean加载,只是在同一个类中,静态代码块优先加载)
探索-源码
入口:
public class TestApplication { | |
public static void main(String[] args) { | |
try { | |
SpringApplication.run(TestApplication.class, args); | |
LOGGER.info("SpringBoot Application Start!!!"); | |
} catch (Throwable e) { | |
throw e; | |
} | |
} | |
} |
其中 里面的run方法为:
public ConfigurableApplicationContext run(String... args) { | |
long startTime = System.nanoTime(); | |
DefaultBootstrapContext bootstrapContext = createBootstrapContext(); | |
ConfigurableApplicationContext context = null; | |
configureHeadlessProperty(); | |
SpringApplicationRunListeners listeners = getRunListeners(args); | |
listeners.starting(bootstrapContext, this.mainApplicationClass); | |
try { | |
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); | |
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); | |
configureIgnoreBeanInfo(environment); | |
Banner printedBanner = printBanner(environment); | |
context = createApplicationContext(); | |
context.setApplicationStartup(this.applicationStartup); | |
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); | |
**refreshContext**(context); | |
afterRefresh(context, applicationArguments); | |
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); | |
if (this.logStartupInfo) { | |
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); | |
} | |
listeners.started(context, timeTakenToStartup); | |
callRunners(context, applicationArguments); | |
} | |
catch (Throwable ex) { | |
handleRunFailure(context, ex, listeners); | |
throw new IllegalStateException(ex); | |
} | |
try { | |
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); | |
listeners.ready(context, timeTakenToReady); | |
} | |
catch (Throwable ex) { | |
handleRunFailure(context, ex, null); | |
throw new IllegalStateException(ex); | |
} | |
return context; | |
} |
refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) { | |
if (this.registerShutdownHook) { | |
shutdownHook.registerApplicationContext(context); | |
} | |
**refresh**(context); | |
} |
AbstractApplicationContext#refresh
然后看倒数第二行:finishBeanFactoryInitialization(beanFactory);
org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException { | |
synchronized (this.startupShutdownMonitor) { | |
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); | |
// Prepare this context for refreshing. | |
prepareRefresh(); | |
// Tell the subclass to refresh the internal bean factory. | |
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); | |
// Prepare the bean factory for use in this context. | |
prepareBeanFactory(beanFactory); | |
// Allows post-processing of the bean factory in context subclasses. | |
postProcessBeanFactory(beanFactory); | |
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); | |
// Invoke factory processors registered as beans in the context. | |
invokeBeanFactoryPostProcessors(beanFactory); | |
// Register bean processors that intercept bean creation. | |
registerBeanPostProcessors(beanFactory); | |
beanPostProcess.end(); | |
// Initialize message source for this context. | |
initMessageSource(); | |
// Initialize event multicaster for this context. | |
initApplicationEventMulticaster(); | |
// Initialize other special beans in specific context subclasses. | |
onRefresh(); | |
// Check for listener beans and register them. | |
registerListeners(); | |
// Instantiate all remaining (non-lazy-init) singletons. | |
**finishBeanFactoryInitialization(beanFactory);** | |
// Last step: publish corresponding event. | |
finishRefresh(); | |
} |
finishBeanFactoryInitialization(beanFactory)
然后看最后一行:beanFactory.preInstantiateSingletons();
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 BeanFactoryPostProcessor | |
// (such as a PropertySourcesPlaceholderConfigurer 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. | |
beanFactory.freezeConfiguration(); | |
// Instantiate all remaining (non-lazy-init) singletons. | |
**beanFactory.preInstantiateSingletons();** | |
} |
beanFactory.preInstantiateSingletons()
在这里会对 beanDefinitionNames 进行遍历,然后进行 bean的实例化 和 组装
因此这里的 beanDefinitionNames 这个列表决定了bean 的 注册顺序。
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() 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. | |
**List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);** | |
// Trigger initialization of all non-lazy singleton beans... | |
for (String beanName : beanNames) { | |
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); | |
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { | |
if (isFactoryBean(beanName)) { | |
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); | |
if (bean instanceof FactoryBean) { | |
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 { | |
getBean(beanName); | |
} | |
} | |
} | |
// Trigger post-initialization callback for all applicable beans... | |
for (String beanName : beanNames) { | |
Object singletonInstance = getSingleton(beanName); | |
if (singletonInstance instanceof SmartInitializingSingleton) { | |
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize") | |
.tag("beanName", beanName); | |
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; | |
if (System.getSecurityManager() != null) { | |
AccessController.doPrivileged((PrivilegedAction<Object>) () -> { | |
smartSingleton.afterSingletonsInstantiated(); | |
return null; | |
}, getAccessControlContext()); | |
} | |
else { | |
smartSingleton.afterSingletonsInstantiated(); | |
} | |
smartInitialize.end(); | |
} | |
} | |
} |
如果不能看,像图中一样,不能找到java.util.list这个类,可以使用下面这个方式,亲测有效:
beanDefinitionNames.toArray()
后面的bean就不展示顺序了。感兴趣的读者可以看自己springBoot项目的。
进一步思考
beanDefinitionNames 列表如何来的呢?
答案是 ConfigurationClassPostProcessor 通过扫描 代码+注解生成的,讲bean 扫描解析成 beanDefinition, 同时把 bean定义,beanDefinition,注册到 BeanDefinitionRegistry, 故有了beanDefinitionNames list。