版本:spring boot 2.2.2
前言
spring boot
设计目的是为了简化 spring
应用初始搭建及开发过程。
优点: 可快速搭建微服务脚手架,无需再配置xml文件,内嵌servlet容器。
spring boot 在代码里直接main函数就可以启动,那到底是怎么去启动一个应用的呢?下面开始分析。
源码分析
public static void main(String[] args) {
//启动方式
SpringApplication.run(Application.class, args);
}
SpringApplication类:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
//返回应用上下文对象
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
//创建一个新实例,将加载应用程序上下文
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//获取web应用类型,返回servlet表示要启动对应的servlet容器,如tomcat
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//加载ApplicationContextInitializer实现类,首次加载spring.factories文件 (spi扩展机制加载)
//spring容器刷新之前初始化,调用实现类initialize方法
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//加载ApplicationListener实现类,从缓存中获取后实例化
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication构造函数主要是加载应用监听类和上下文初始化类,通过查找类路径下文件解析并获取其配置的实现类
下面来看run方法函数
//
public ConfigurableApplicationContext run(String... args) {
//记录启动运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//一: 创建监听实现类EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//二:准备应用环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//创建打印类
Banner printedBanner = printBanner(environment);
//三:创建应用程序上下文
context = createApplicationContext();
//创建异常处理回调接口类
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//四:准备应用上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//五:刷新应用上下文
refreshContext(context);
//扩展接口,刷新后处理
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//发布应用上下文启动事件
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//发布应用上下文运行事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
下面分步骤来了解启动过程。
一:创建监听实现类EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
//获取运行监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//类加载器加载类路径下 META-INF/spring.factories 文件中的限定类名
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//加载及创建实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
spring.factories文件中配置的监听类:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
listeners.starting();
EventPublishingRunListener类:
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
//加入spring.factories文件中配置的监听类
this.initialMulticaster.addApplicationListener(listener);
}
}
public void starting() {
//发布应用启动事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
SimpleApplicationEventMulticaster类:
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);
}
}
}
...
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
//执行监听器事件
listener.onApplicationEvent(event);
...省略异常代码
}
二:准备应用环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
注: bindToSpringApplication()
:将环境绑定到SpringApplication类,下文2.3已说明本次环境依赖spring cloud jar包,所以配置文件加载优先级:
-
bootstrap.yml
-
application.yml 配置文件属性通过反射注入SpringApplication对象属性值。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 2.1 创建环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//2.2 对属性源和配置文件进行配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
//将属性源支持附加到指定的环境
ConfigurationPropertySources.attach(environment);
//2.3 发布环境已准备事件
listeners.environmentPrepared(environment);
//将环境绑定到spring 应用
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
2.1 创建环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
StandardServletEnvironment创建对象时会加入一组属性源 属性源名称按添加顺序排序:
-
servletConfigInitParams: Servlet配置初始化参数
-
servletContextInitParams: Servlet上下文初始化参数
-
systemProperties: 系统环境
-
systemEnvironment: JVM系统属性
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
//SpringApplication初始化时已被设置为servlet类型,此时创建标准servlet环境对象
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
//标准环境对象,spring cloud初始化时会创建
return new StandardEnvironment();
}
}
2.2 对属性源和配置文件进行配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
//创建类型转换的服务接口,添加格式化程序和转换器
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}
//模板方法,可重写
//从环境对象中获取属性源进行配置,如设置命令行属性源,用于获取命令行设置的参数
configurePropertySources(environment, args);
//配置默认的profiles环境标识
configureProfiles(environment, args);
}
2.3 发布环境已准备事件
listeners.environmentPrepared(environment);
本项目用到了spring cloud
的部分组件,如spring cloud config, ribbon组件等,有依赖spring-cloud-context.jar, 所以在SpringApplication初始化时会加载BootstrapApplicationListener
监听器,此监听器用于创建spring cloud应用上下文
根据事件类型获取到的监听器:
2.3.1 分析BootstrapApplicationListener监听器
BootstrapApplicationListener类:
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
//禁用bootstrap配置过程
if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
true)) {
return;
}
//不监听bootstrap上下文事件
if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
return;
}
ConfigurableApplicationContext context = null;
//读取环境配置属性,默认bootstarp
String configName = environment
.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
.getInitializers()) {
//ParentContextApplicationContextInitializer:设置父上下文,添加应用监听
if (initializer instanceof ParentContextApplicationContextInitializer) {
context = findBootstrapContext(
(ParentContextApplicationContextInitializer) initializer,
configName);
}
}
if (context == null) {
//重点:创建bootstrap上下文,初始化spring cloud环境对象
context = bootstrapServiceContext(environment, event.getSpringApplication(),
configName);
//监听启动失败事件,用于关闭bootstartp上下文,销毁bean
event.getSpringApplication()
.addListeners(new CloseContextOnFailureApplicationListener(context));
}
apply(context, event.getSpringApplication(), environment);
}
private ConfigurableApplicationContext bootstrapServiceContext(
ConfigurableEnvironment environment, final SpringApplication application,
String configName) {
//新建bootstrap环境对象
StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
......
Map<String, Object> bootstrapMap = new HashMap<>();
//添加bootstarp配置名
bootstrapMap.put("spring.config.name", configName);
bootstrapMap.put("spring.main.web-application-type", "none");
SpringApplicationBuilder builder = new SpringApplicationBuilder()
.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
.environment(bootstrapEnvironment)
.registerShutdownHook(false).logStartupInfo(false)
//NONE: 获取非web应用程序的上下文环境,不会启动web容器(tomcat)
.web(WebApplicationType.NONE);
final SpringApplication builderApplication = builder.application();
......
//将BootstrapImportSelector类注入容器并获取BootstrapConfiguration 配置类
builder.sources(BootstrapImportSelectorConfiguration.class);
//创建bootstarp上下文
final ConfigurableApplicationContext context = builder.run();
//设置上下文id
context.setId("bootstrap");
//将bootstrap上下文设置为当前应用的父上下文
addAncestorInitializer(application, context);
bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
//合并属性源
mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
return context;
}
2.3.2 分析ConfigFileApplicationListener监听器
此监听器用于加载配置文件,在创建bootstrap上下文中会加载配置的bootstrap.yml文件。
builder.run()调用后会在prepareEnvironment 方法中执行环境已准备事件,获取到ConfigFileApplicationListener监听器,在onApplicationEvent方法中由于当前是环境已准备事件,调用onApplicationEnvironmentPreparedEvent方法将其自身加入环境配置的集合。
ConfigFileApplicationListener类
//默认搜索路径
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
@Override
public void onApplicationEvent(ApplicationEvent event) {
//环境已准备事件
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//获取环境变量扩展类
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
//自身加入集合执行
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
//加载配置文件
new Loader(environment, resourceLoader).load();
}
}
创建内部类Loader,初始化构造函数时通过spi方法加载不同的配置实现类。
-
YamlPropertySourceLoader
:加载.yml、.yaml格式的文件 -
PropertiesPropertySourceLoader
:加载.properties格式的文件
具体路径:默认搜索路径 + 配置属性名 + 文件扩展名 例子:classpath:/bootstarp.yml
private class Loader {
...
void load() {
FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
(defaultProperties) -> {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
//初始化默认属性值 null,default
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (isDefaultProfile(profile)) {
addProfileToEnvironment(profile.getName());
}
//第一次进入,profile等于空,此时是spring cloud环境属性,根据上面的搜索路径,会找到bootstrap.yml文件,读取文件中配置的spring.profiles.active属性,读到后加入profiles属性集合,移除掉default属性值。
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
applyActiveProfiles(defaultProperties);
});
}
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/");
Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
});
}
private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
DocumentConsumer consumer) {
...
Set<String> processed = new HashSet<>();
//properties,ymal 两个文件扩展实现类
for (PropertySourceLoader loader : this.propertySourceLoaders) {
for (String fileExtension : loader.getFileExtensions()) {
if (processed.add(fileExtension)) {
loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
consumer);
}
}
}
}
}
后续会详细出spring cloud上下文加载流程, spring cloud依赖组件多,篇幅有限。此处就分析到这。下面继续分析spring boot后续流程。
三:创建应用程序上下文
context = createApplicationContext();
Class.forName()初始化AnnotationConfigServletWebServerApplicationContext类,执行静态代码块,此时没有实例化该类。通过instantiateClass方法中调用newInstance方法实例化,此时会调用父类GenericApplicationContext构造函数,执行DefaultListableBeanFactory类的实例化操作。 DefaultListableBeanFactory是默认IOC容器实现类, BeanFactory是顶层容器抽象接口,为具体的容器实现类提供了基本的规范。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
//创建servlet web上下文,后面会启动tomcat
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
//spring cloud创建上下文对象
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
//反射创建对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
四:准备应用上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
SpringApplication类:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//设置上下文环境
context.setEnvironment(environment);
//应用后置处理,设置服务转换接口
postProcessApplicationContext(context);
//初始化应用上下文
applyInitializers(context);
//发布上下文已初始化事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册单例bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
//设置是否允许同名的bean注册,默认false,重复注册抛异常 true:自动覆盖前者
//上文有讲,如果bootstrap.yml 和 application.yml都配置了allowBeanDefinitionOverriding属性,会读取bootstrap.yml文件的值,忽略后面的文件
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 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);
}
注:
-
bootstrap上下文加载时,配置文件 bootstrap.yml 优先于 application.yml 加载,查到属性值后不往后查找。例如 SpringApplication 对象中 allowBeanDefinitionOverriding 属性,优先会加载bootstrap.yml中配置的值。
-
Spring boot应用上下文加载时,会在 prepareContext() -> applyInitializers(context) -> AncestorInitializer.initialize(context) 代码中将bootstrap.yml属性源移除后重新添加到数组尾部,所以后面查找属性源配置application.yml优先于bootstrap.yml。例如后面的tomcat端口配置 server.port,会优先加载application.yml中配置的端口。
五:刷新应用上下文
refreshContext(context);
//AbstractApplicationContext类
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前准备工作,初始化占位符属性源及校验必须属性
prepareRefresh();
// 让子类刷新内部bean工厂,设置序列化id
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置工厂的标准上下文特性,例如上下文的类加载器和后处理器
prepareBeanFactory(beanFactory);
try {
//5.1 允许在上下文子类中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);
// 5.2 调用在上下文中注册为 bean 的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 5.3 注册拦截bean 创建的 bean 处理器
registerBeanPostProcessors(beanFactory);
// 初始化消息国际化处理
initMessageSource();
// 初始化事件广播器
initApplicationEventMulticaster();
//初始化主题源, 启动tomcat服务并初始化监听
onRefresh();
// 添加监听事件,发布早期监听事件
registerListeners();
// 5.4 完成这个上下文的bean工厂的初始化,初始化所有剩余的单例 bean
finishBeanFactoryInitialization(beanFactory);
// 完成此上下文刷新,发布上下文已刷新事件
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 {
//重置元数据缓存信息
resetCommonCaches();
}
}
}
5.1 允许在上下文子类中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);
//AnnotationConfigServletWebServerApplicationContext类
@Override
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));
}
}
后处理bean扩展接口:
-
BeanFactoryPostProcessor 容器初始化之后触发,bean实例化之前执行
-
BeanPostProcessor 针对某个具体的bean处理,对象初始化时触发,如initMethod方法前后
//ServletWebServerApplicationContext类
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//添加 BeanPostProcessor 后置处理器, 该后置处理器主要是从 ConfigurableWebApplicationContext 上下文中获取 ServletContext 和 ServletConfig 对象
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
//ServletContextAware:返回当前的servlet上下文
//自动注入时忽略指定依赖接口中set方法的自动装配方式
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
//注册web应用的scopes
registerWebApplicationScopes();
}
5.2 调用在上下文中注册为 bean 的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
该方法遍历所有的beanFactoryPostProcessors, 将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开,执行对应的postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法。 其中ConfigurationClassPostProcessor是一个BeanFactory的后置处理器,在这个类中,会解析@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。
如果业务需手动向spring ioc容器注入bean, 可实现BeanFactoryPostProcessor接口,重写
postProcessBeanFactory方法;
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory)方法会执行自定义bean工厂处理逻辑。
注:
-
BeanDefinitionRegistry: 主要是向注册表中注册 BeanDefinition 实例,完成注册的过程。
-
BeanDefinitionRegistryPostProcessor: 对BeanDefinition进行一些后置处理,比如完成新的BeanDefinition注册,对已有BeanDefinition进行修改等操作。
下面我们看下代码自定义的bean是怎么注册到beanFactory的:
直接看bean definition扫描器类-ClassPathBeanDefinitionScanner
//ClassPathBeanDefinitionScanner类
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//扫描包路径获取BeanDefinition, 默认过滤掉不包含@Component的类
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//处理@Scope注解元数据
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//生成beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查beanDefinition是否冲突
if (checkCandidate(beanName, candidate)) {
//创建 definitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//对 BeanDefinitionHolder 填充代理信息
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册 BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
此时代码里定义的bean已注册到spring容器中,放在beanDefinitionMap中
// DefaultListableBeanFactory类
// 存放bean对象的集合
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
this.beanDefinitionMap.put(beanName, beanDefinition);
5.3 注册拦截bean 创建的 bean 处理器
registerBeanPostProcessors(beanFactory);
该方法的作用是找到所有的BeanPostProcessor,然后调用getBean实例化, 实例化后,最后放入到BeanFactory的beanPostProcessors属性中。
PostProcessorRegistrationDelegate#registerBeanPostProcessors方法会将后置处理器AutowiredAnnotationBeanPostProcessor加入bean工厂,
该后置处理器会注入依赖的属性,如果依赖没有实例化会先实例化,然后反射进行赋值。
5.4 完成这个上下文的bean工厂的初始化,初始化所有剩余的单例 bean
finishBeanFactoryInitialization(beanFactory);
finishBeanFactoryInitialization方法中会执行beanFactory.preInstantiateSingletons(),来实例化所有剩余的(非延迟初始化)单例。
//DefaultListableBeanFactory
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// bean definition名字集合
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
//合并bean
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象、单例、非懒加载bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
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 {
//获取bean
getBean(beanName);
}
}
}
省略...
}
AbstractAutowireCapableBeanFactory#doGetBean方法格式化beanName名称,其中getSingleton(beanName) 返回已注册单例对象, 避免循环依赖,已实例化对象放入singletonObjects集合。未找到bean实例则调用 createBean -> doCreateBean方法实例化bean, 后执行populateBean方法时会注入依赖的对象,查找依赖的属性对象时先去缓存中查找,未查到,也走createBean流程。
到此spring流程比较简单的分析完了。
总结:
-
Springboot启动创建一个SpringApplication对象,其构造方法里获取web应用类型,加载初始化器、加载监听类,然后执行run方法;
-
run方法主要是创建监听实现类、准备应用环境(prepareEnvironment)、创建应用程序上下文(createApplicationContext)、准备应用上下文(prepareContext)、刷新应用上下文(refreshContext)、以及后续的发布事件;
-
prepareEnvironment方法创建上下文,对属性源进行配置,将环境绑定到SpringApplication上下文;
-
createApplicationContext方法初始化web应用上下文,实例化该对象,此时执行父类构造函数时会实例化ioc容器实现类DefaultListableBeanFactory;
-
prepareContext方法初始化上下文环境、加载启动类、发布上下文加载事件;
-
refreshContext方法对bean工厂后处理、注册bean实例,启动tomcat, 实例化单例bean, 发布上下文已刷新事件;
-
发布应用上下文运行事件,返回容器,启动类启动完成。此时虚拟机不会退出,tomcat启动时创建了非守护线程,java应用内任何非守护线程还在运行,守护线程就不会终止。