1 整体流程
Springboot的启动核心run方法如下
代码语言:javascript复制public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
// 1.创建BootstrapContext
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 2.headless模式配置
configureHeadlessProperty();
// 3.获取SpringApplicationRunListeners,执行starting方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 4.解析应用的启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5.准备运行时环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 6.是否忽略BeanInfo类的搜索
configureIgnoreBeanInfo(environment);
// 7.打印Banner
Banner printedBanner = printBanner(environment);
// 8.创建ApplicationContext
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 9.初始化IOC容器
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 10.刷新IOC容器
refreshContext(context);
// 11.刷新后处理
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
// 12.回调Runner
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;
}
从以上代码中可以看出,整个启动流程还是比较清晰的,下面依次来看看每个步骤的具体逻辑
2 DefaultBootstrapContext
先简单介绍下DefaultBootstrapContext,它是BootstrapContext的一个默认实现,作用是可以用于为创建复杂的单例,或者是需要在容器初始化之前使用的单例,并且提供了延迟访问的机制,延迟访问主要是通过InstanceSupplier实现,下文中有讲到。
使用的时机如下图所示
启动开始时,在listeners.starting(bootstrapContext,this.mainApplicationClass)处使用
在准备ConfigurableEnvironment时使用
最后在prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner)方法中,在listeners执行完contextPrepared方法后调用了DefaultBootstrapContext的close方法,close方法发布了一个BootstrapContextClosedEvent事件,可见在此之后DefaultBootstrapContext的生命周期就结束了
DefaultBootstrapContext中的核心方法和属性如下
持有两个Map,instances和instanceSuppliers,其中instances是存储对象实例,instanceSuppliers存储对象实例的提供者(可以理解为实例的工厂),它们的key是class对象,因此是用于单例的存储
events是个事件广播器,上面讲到的关闭事件就是用它发布的
close监听及事件相关的方法,用于发布关闭事件,回调监听者
get方法,获取的是instances中存储的实例,结合代码可以看到instances中的实例又是由instanceSuppliers生产提供
register方法,注册的是instanceSupplier,用于生产instance实例
下面来看看流程中第一步createBootstrapContext()
代码语言:javascript复制private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
其实就是使用了bootstrapRegistryInitializers,依次调用initializer.initialize方法初始化,而bootstrapRegistryInitializers的获取是在SpringApplication的构造器中通过getSpringFactoriesInstances方法获取,如下
代码语言:javascript复制public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
在getSpringFactoriesInstances方法中其实最终就是利用Springboot的SPI机制从spring.factories文件中加载bootstrapRegistryInitializers,并且在以上代码中还获取ApplicationListener和ApplicationContextInitializer,后文中分析其作用
3 Headless配置
Headless模式是系统的一种配置模式,在该模式下,系统缺少了显示设备、键盘或鼠标。 Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机),此时就可以使用Headless模式来提供简单的显示设备、键盘或鼠标的功能,代码比较简单,如下
代码语言:javascript复制private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
如果配置了SYSTEM_PROPERTY_JAVA_AWT_HEADLESS就使用配置的值,否则使用默认值(true)
4 SpringApplicationRunListeners
SpringApplicationRunListener是在整个启动流程中不同执行点事件通知的监听者,接口定义如下
代码语言:javascript复制public interface SpringApplicationRunListener {
// run方法被调用后立即执行
default void starting(ConfigurableBootstrapContext bootstrapContext) {}
// 当environment构建完成,ApplicationContext创建之前执行
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {}
// 当ApplicationContext创建完成,但是资源还没有加载之前执行
default void contextPrepared(ConfigurableApplicationContext context) {}
// 当ApplicationContext资源加载完成,但是刷新之前执行
default void contextLoaded(ConfigurableApplicationContext context) {}
// 当ApplicationContext刷新并启动之后,但是CommandLineRunner和ApplicationRunner执行之前执行
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
started(context);
}
// 同上,但是已经被弃用since 2.6.0
@Deprecated
default void started(ConfigurableApplicationContext context) {}
// 在run方法完成之前执行
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
running(context);
}
// 同上,但是已经被弃用since 2.6.0
@Deprecated
default void running(ConfigurableApplicationContext context) {}
// 在run方法抛异常的时候执行
default void failed(ConfigurableApplicationContext context, Throwable exception) {}
}
获取SpringApplicationRunListener的方法也比较简单,就是利用Springboot的SPI机制从spring.factories文件中加载,如下
代码语言:javascript复制private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
在启动的过程当中,只加载了一个SpringApplicationRunListener,就是EventPublishingRunListener
获取到EventPublishingRunListeners之后,调用了listeners.starting(bootstrapContext,this.mainApplicationClass)方法
代码语言:javascript复制void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
在starting方法中依次调用各个listener的starting方法,所有来看看EventPublishingRunListener的starting方法,如下
代码语言:javascript复制public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
可以看到就是利用initialMulticaster发布了一个ApplicationStartingEvent事件。
到这里简单总结下,在启动调用run方法之后立即调用SpringApplicationRunListeners的starting方法,而SpringApplicationRunListeners是一个代理,内部维护了一个SpringApplicationRunListener列表,启动时只加载了一个EventPublishingRunListener,然后通过EventPublishingRunListener发布一个ApplicationStartingEvent事件,那又是谁来监听ApplicationStartingEvent呢,继续看multicastEvent方法
代码语言:javascript复制public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
从上面代码可以看出multicastEvent方法中又调用getApplicationListeners方法根据事件类型获取了对应的ApplicationListener,而getApplicationListeners又调用了retrieveApplicationListeners方法,如下
代码语言:javascript复制private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
......
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
......
}
在retrieveApplicationListeners方法中我们看到这里主要从this.defaultRetriever中获取ApplicationListener,而defaultRetriever的ApplicationListener又是从哪里来的呢?这里的this对象是initialMulticaster,所以我们再回过头看看在initialMulticaster的创建过程,如下
代码语言:javascript复制public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
initialMulticaster是在EventPublishingRunListener的构造方法中创建,并且从SpringApplication中获取ApplicationListener并且通过initialMulticaster.addApplicationListener方法添加,如下
代码语言:javascript复制public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
在addApplicationListener方法中将ApplicationListener添加到defaultRetriever,而SpringApplication中的ApplicationListener是在新建SpringApplication对象是从spring.factories文件中加载,上面已经提到过。
5 PrepareEnvironment
第四步解析启动参数比较简单就略过,下面来看看运行时环境准备,代码如下
代码语言:javascript复制private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 根据webApplicationType创建environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置environment
configureEnvironment(environment, applicationArguments.getSourceArgs());
// attachsources
ConfigurationPropertySources.attach(environment);
// 发布environmentPrepared事件
listeners.environmentPrepared(bootstrapContext, environment);
// 将默认的source移到最后
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
// 绑定spring.main开头的属性配置到SpringApplication对应的field
bindToSpringApplication(environment);
// 判断environment是否需要转换
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 重新再attachsources一次
ConfigurationPropertySources.attach(environment);
return environment;
}
下面依次看看各个步骤
getOrCreateEnvironment(),代码如下
代码语言:javascript复制// 本质上是遍历所有的ApplicationContextFactory实例(也是
// 从spring.factories文件中加载),看和webApplicationType是否匹配,匹配就创建对应的environment
// spring有两种ApplicationContextFactory,如下
// AnnotationConfigReactiveWebServerApplicationContext$Factory,webfluxserver
// AnnotationConfigServletWebServerApplicationContext$Factory,servletserver
// 这里最终创建的是ApplicationServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
ConfigurableEnvironment environment = this.applicationContextFactory.createEnvironment(this.webApplicationType);
if (environment == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {
environment = ApplicationContextFactory.DEFAULT.createEnvironment(this.webApplicationType);
}
return (environment != null) ? environment : new ApplicationEnvironment();
}
configureEnvironment(environment, applicationArguments.getSourceArgs()),代码如下
代码语言:javascript复制// 为environment设置ApplicationConversionService,主要是做类型转换和格式化的
// 另外还将命令行参数也设置到environment中,configureProfiles为空实现
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
ConfigurationPropertySources.attach(environment),代码如下
代码语言:javascript复制// 将名称为configurationProperties的PropertySource添加到第一个,优先级最高
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
PropertySource<?> attached = getAttached(sources);
if (attached == null || !isUsingSources(attached, sources)) {
attached = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
new SpringConfigurationPropertySources(sources));
}
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
sources.addFirst(attached);
}
listeners.environmentPrepared(bootstrapContext, environment)和listeners.starting类似发布了一个ApplicationEnvironmentPreparedEvent事件,然后获取到对应事件的EnvironmentPostProcessor处理器列表依次处理,我们的默认application.properties和application-{profile}.properties就是在这些处理器中加载的(处理器的逻辑就不一一列举了),如下所示
DefaultPropertiesPropertySource.moveToEnd(environment),将名称为defaultProperties的移动到最后,优先级最低
代码语言:javascript复制public static void moveToEnd(MutablePropertySources propertySources) {
PropertySource<?> propertySource = propertySources.remove(NAME);
if (propertySource != null) {
propertySources.addLast(propertySource);
}
}
bindToSpringApplication(environment),如果配置文件中配置了以spring.main开头的属性配置,在这里会绑定到SpringAppliction类对应的field上
代码语言:javascript复制protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
}
catch (Exception ex) {
throw new IllegalStateException("Cannot bind to SpringApplication", ex);
}
}
environment = environmentConverter.convertEnvironmentIfNecessary(environment,deduceEnvironmentClass()),这里是判断environment是否需要转换,其实这里创建的environment就是根据Type去创建出来的,所以一般类型是吻合的,不需要转换,最后再次执行attachResource,将configurationProperties属性源优先级提到最高,这样environment就准备完成了
6 是否忽略BeanInfo类的搜索
设置是否忽略BeanInfo类的搜索,spring在根据Class获取BeanInfo时是通过Java的Introspector工具获取,获取的时候可以设置是否忽略BeanInfo类的搜索,默认是不忽略,如下所示
代码语言:javascript复制BeanInfo beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
Introspector.getBeanInfo(beanClass));
代码语言:javascript复制private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
7 创建ApplicationContext
打印Banner部分就不看了,直接看创建ApplicationContext
代码语言:javascript复制protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
和environment一样通过applicationContextFactory创建,applicationContextFactory.create——>getFromSpringFactories
代码语言:javascript复制private <T> T getFromSpringFactories(WebApplicationType webApplicationType,
BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
getClass().getClassLoader())) {
T result = action.apply(candidate, webApplicationType);
if (result != null) {
return result;
}
}
return (defaultResult != null) ? defaultResult.get() : null;
}
上文中提到applicationContextFactory只有两种实现,AnnotationConfigReactiveWebServerApplicationContext$Factory和 AnnotationConfigServletWebServerApplicationContext$Factory,所以这里是通过后者的create方法创建,继续跟进
代码语言:javascript复制public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.SERVLET) ? null
: new AnnotationConfigServletWebServerApplicationContext();
}
AnnotationConfigServletWebServerApplicationContext$Factory的create方法就只是New了一个AnnotationConfigServletWebServerApplicationContext出来直接返回,看下构造方法做了什么
代码语言:javascript复制public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
如上,构造方法定义了reader的scanner,这两个类都是用来加载BeanDefinition,scanner主要是用来扫描指定的包下带注解的类,而reader主要是用来动态显示注册一些spring扫描不到的类,比如spring完成扫描是需要解析Appconfig.java当中的@ComponentScan注解的值(一般是一个包名),得到这个值之后用scanner去扫描这个值所代表的包下面的所有bean,由于这里使用的是AnnotationConfigServletWebServerApplicationContext的无参构造器,所以会先依次调用父类的无参构造器
这里看下父类GenericApplicationContext的无参构造器
代码语言:javascript复制public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
可以看到在这里新建了beanFactory,使用的是DefaultListableBeanFactory
再来看看新建AnnotatedBeanDefinitionReader时做了什么
代码语言:javascript复制public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
新建AnnotatedBeanDefinitionReader时最终是调用以上的构造器创建,最后一行注册了一些基础的处理器,比如处理@Autowired自动注入的processor,如下
8 初始化IOC容器
ApplicationContext创建好了之后开始初始化IOC容器,初始化代码如下
代码语言:javascript复制private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
下面依次看看各个步骤
context.setEnvironment(environment),为context、reader、scanner设置运行时环境
代码语言:javascript复制public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
postProcessApplicationContext(context),如果我们在初始化SpringApplication时为之设置了beanNameGenerator或resourceLoader,则会在此方法中注册到BeanFactory或设置到ApplicationContext。除此之外,ConversionService是初始化Environment时候就有的,也会在这里被设置到BeanFactory
代码语言:javascript复制protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory()
.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
}
applyInitializers(context),首先initializers列表,在新建SpringApplication时就已经通过SPI加载了,然后依次调用ApplicationContextInitializer的initialize方法
代码语言:javascript复制protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
bootstrapContext.close(context),bootstrapContext的生命周期到此就结束了,发布了一个close事件
logStartupInfo主要就是在打印banner之后打印一些启动信息,如下
之后就是注册ApplicationArgrument和Banner,设置BeanFactory是否循序循环引用,是否允许覆盖注册,默认都是false
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()),如果需要延迟初始化,默认false,则需要注册一个LazyInitializationBeanFactoryPostProcessor,在BeanDefinition加载完成之后将BeanDefinition的lazyInit属性设置成true,如下
代码语言:javascript复制public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Collection<LazyInitializationExcludeFilter> filters = getFilters(beanFactory);
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition instanceof AbstractBeanDefinition) {
postProcess(beanFactory, filters, beanName, (AbstractBeanDefinition) beanDefinition);
}
}
}
private void postProcess(ConfigurableListableBeanFactory beanFactory,
Collection<LazyInitializationExcludeFilter> filters, String beanName,
AbstractBeanDefinition beanDefinition) {
Boolean lazyInit = beanDefinition.getLazyInit();
if (lazyInit != null) {
return;
}
Class<?> beanType = getBeanType(beanFactory, beanName);
if (!isExcluded(filters, beanName, beanDefinition, beanType)) {
beanDefinition.setLazyInit(true);
}
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context)),注册一个PropertySourceOrderingBeanFactoryPostProcessor,主要作用是再次将defaultProperties属性源的优先级调到最低,如下
代码语言:javascript复制public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultPropertiesPropertySource.moveToEnd(this.context.getEnvironment());
}
Set<Object> sources = getAllSources(),获取primarySources和sources,primarySources就是引用的启动类,sources默认是空
代码语言:javascript复制public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
load(context, sources.toArray(newObject[0]))
代码语言:javascript复制protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
load方法中先是通过getBeanDefinitionRegistry方法获取了BeanDefinitionRegistry,因为当前应用上下文实际类型为AnnotationConfigServletWebServerApplicationContext,从类继承关系中可以找到该类实现了BeanDefinitionRegistry,所以getBeanDefinitionRegistry方法返回的就是当前应用上下文自身,如下
代码语言:javascript复制private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
if (context instanceof BeanDefinitionRegistry) {
return (BeanDefinitionRegistry) context;
}
if (context instanceof AbstractApplicationContext) {
return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
然后创建了BeanDefinitionLoader,这里其实就新建了各种加载器
代码语言:javascript复制BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
最后通过loader.load加载
代码语言:javascript复制void load() {
for (Object source : this.sources) {
load(source);
}
}
private void load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
load((Class<?>) source);
return;
}
if (source instanceof Resource) {
load((Resource) source);
return;
}
if (source instanceof Package) {
load((Package) source);
return;
}
if (source instanceof CharSequence) {
load((CharSequence) source);
return;
}
throw new IllegalArgumentException("Invalid source type " source.getClass());
}
由于source是一个class类型(启动类),所以走到load(Class<?> source)方法,如下
代码语言:javascript复制private void load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
}
if (isEligible(source)) {
this.annotatedReader.register(source);
}
}
最终走到this.annotatedReader.register(source)方法,里面的方法就不跟进了,其实就只把启动类注册到registry中
listeners.contextLoaded(context),当load加载完之后最后发布一个ApplicationPreparedEvent事件
9 刷新IOC容器
来到最重要的流程,刷新IOC容器
代码语言:javascript复制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);
try {
// 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();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - "
"cancelling refresh attempt: " ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
同样依次看看每个步骤的逻辑
prepareRefresh(),刷新前的准备操作,如下
代码语言:javascript复制protected void prepareRefresh() {
// 设置active状态
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " this);
}
else {
logger.debug("Refreshing " getDisplayName());
}
}
// 设置servletContext和servletConfig的source(如果有)
initPropertySources();
// 校验必填属性(默认没有,可以通过setRequiredProperties设置)
getEnvironment().validateRequiredProperties();
// 初始化earlyApplicationListeners
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 初始化earlyApplicationEvents
this.earlyApplicationEvents = new LinkedHashSet<>();
}
obtainFreshBeanFactory(),获取BeanFactory,refreshBeanFactory()方法其实啥也没做,只是为BeanFactory设置了一个id
代码语言:javascript复制protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
prepareBeanFactory(beanFactory),准备BeanFactory
代码语言:javascript复制protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置ClassLoader
beanFactory.setBeanClassLoader(getClassLoader());
// 设置beanFactory表达式解析器,可以通过#beanName.xxxx来获取相关的属性或者调用相关的方法
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
// 添加一个bean的属性转换器,比如属性是一个Object类型,但是在xml中是以字符串的形式配置的,
// 就可以通过转换器互相转换
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 设置ApplicationContextAwareProcessor,它是一个BeanPostProcessor接口的实现,在Bean初始化之前
// 设置各种Aware接口的实现,常用的ApplicationContextAware这些就是通过这个Processor来处理的
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 跳过以下接口的自动注入,因为这些是在ApplicationContextAwareProcessor中处理
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.ignoreDependencyInterface(ApplicationStartupAware.class);
// 设置几个"自动装配"规则,如下:
// 如果是 BeanFactory 的类,就注册 beanFactory
// 如果是 ResourceLoader、ApplicationEventPublisher、ApplicationContext 等,
// 就注入当前对象 this(applicationContext对象)
// 此处 registerResolvableDependency() 会把它们加入到 DefaultListableBeanFactory 的
// resolvableDependencies 字段里面缓存,供后面处理依赖注入的时候使用,
// DefaultListableBeanFactory#resolveDependency 处理依赖关系
// 这也是为什么我们可以通过依赖注入的方式直接注入这几个对象,比如 ApplicationContext 可以直接依赖注入
// 但是需要注意的是:这些 Bean,Spring 的 IOC 容器里其实是没有的。
// beanFactory.getBeanDefinitionNames() 和 beanFactory.getSingletonNames() 都是找不到它们的,
// 特别需要理解这一点
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加到ApplicationListenerDetector,它是一个BeanPostProcessor接口的实现,如果Bean实现了
// ApplicationListener接口,则将其加入到当前applicationContext的applicationListeners列表
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 检查容器中是否包含名称为 loadTimeWeaver 的 bean,实际上是增加 Aspectj 的支持
// AspectJ是一种静态代理技术,可以在编译期、编译后或者类加载期进行织入
// 而类加载期织入简称为 LTW(Load Time Weaving),通过特殊的类加载器来代理 JVM 默认的类加载器实现
if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
// 添加 Bean 后置处理器:LoadTimeWeaverAwareProcessor
// 在 Bean 初始化之前检查 Bean 是否实现了 LoadTimeWeaverAware 接口,如果是,
// 则进行加载时织入
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册environment相关的Bean,比如environment、systemProperties、SystemEnvironment等
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());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
}
postProcessBeanFactory(beanFactory),主要就是注册了一些servlet相关的BeanPostProcessor以及注册了servletContext、servletConfig等bean,这里basePackages和annotatedClasses都是空,所以不会执行scan和register
代码语言:javascript复制protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
invokeBeanFactoryPostProcessors(beanFactory),执行所有BeanFactoryPostProcessor的实现
代码语言:javascript复制protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
可以看出主要是通过PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法来执行,接着又是添加AspectJ的支持,上个步骤中已经添加过了,所有这里不会执行,先来看看getBeanFactoryPostProcessors()方法
代码语言:javascript复制public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
直接返回当前ApplicationContext的beanFactoryPostProcessors属性,下面来看看PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,这个方法比较复杂,总的来说就是执行容器中所有实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的类的方法,BeanDefinitionRegistryPostProcessor优于BeanFactoryPostProcessor执行,所以如果要加载自定义的BeanDefinition,这里是一个比较重要的扩展点,代码如下
代码语言:javascript复制public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 这里拿到的beanFactoryPostProcessors有第三个,分别是
// CachingMetadataReaderFactoryPostProcessor
// ConfigurationWarningsPostProcessor
// PropertySourceOrderingBeanFactoryPostProcessor
// 先将实现了BeanDefinitionRegistryPostProcessor接口的Processor挑出来执行
// 其他的加入regularPostProcessors待执行
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// CachingMetadataReaderFactoryPostProcessor注册了一个SharedMetadataReaderFactoryBean
// ConfigurationWarningsPostProcessor打印了一些警告信息
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// PropertySourceOrderingBeanFactoryPostProcessor添加到regularPostProcessors待执行
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 从beanFactory中获取注册了的实现了BeanDefinitionRegistryPostProcessor接口的beanName
// 并且从中挑选出实现了PriorityOrdered接口的Bean加入到currentRegistryProcessors
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 对currentRegistryProcessors排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行currentRegistryProcessors,这里拿到的processor只有一个就是ConfigurationClassPostProcessor
// 这个processor非常重要,加载了所有的Bean(@Controller, @Service,@Configuration等等)
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
// 清除currentRegistryProcessors
currentRegistryProcessors.clear();
// 再从beanFactory中获取注册了的实现了BeanDefinitionRegistryPostProcessor接口的beanName
// 并且从中挑选出实现了Ordered接口的Bean加入到currentRegistryProcessors
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);
}
}
// 执行实现了Ordered接口的BeanDefinitionRegistryPostProcessor,默认没有
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 最后循环从beanFactory中获取注册了的实现了BeanDefinitionRegistryPostProcessor接口的beanName
// 然后依次执行其postProcessBeanDefinitionRegistry方法
// 直到没有新的BeanDefinitionRegistryPostProcessor出现
// 假如用了mybatis,这其中就包括了mybatis的Mapper扫描
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, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
// 最后再去执行所有processor的postProcessBeanFactory方法
// 实现了BeanDefinitionRegistryPostProcessor接口的先执行
// BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的一个子接口
// 所以实现了BeanDefinitionRegistryPostProcessor接口必然要实现BeanFactoryPostProcessor接口
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 最后再找到所有实现了BeanFactoryPostProcessor接口的Bean,并且按照PriorityOrdered,Ordered以及没有
// 排序的分开依次执行其postProcessBeanFactory方法
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
由于文章字数限制,后续分析请看Spring系列二之springboot启动(下)