一、入口
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
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;
}
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
这个方法主要是一些准备工作,用来进行一些赋值操作,在上一步中已经把应用上下文创建出来了,这里就是赋值,会去创建一些 bean 对象存于 IOC容器中,会完成主类(启动类)对象的创建并添加到 IOC 容器中 ,接着看 prepareContext方法的具体实现
二、prepareContext 方法实现
截图:
代码:
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();
// 将 main 主函数中的 args 参数封装成单例 bean ,注册进容器
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((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);
}
接着看 applyInitializers 方法实现
2.1 applyInitializers 方法实现
引:applyInitializers(context);
截图:
代码:
/**
* Apply any {@link ApplicationContextInitializer}s to the context before it is
* refreshed.
* @param context the configured ApplicationContext (not refreshed yet)
* @see ConfigurableApplicationContext#refresh()
*/
// 之前在 new SpringApplication() 中创建的初始化容器的启动
@SuppressWarnings({ "rawtypes", "unchecked" })
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);
}
}
initializer.initialize(context);这个方法就会启动一些上下文
2.2 load 方法实现
引:load(context, sources.toArray(new Object[0]));
截图:
代码:
/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 创建 BeanDefinitionLoader
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();
}
点击loader.load()方法,又调用了load()方法:
截图:
代码:
/**
* Load the sources into the reader.
* @return the number of loaded beans
*/
int load() {
int count = 0;
for (Object source : this.sources) {
count += load(source);
}
return count;
}
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
// 从 Class 加载
return load((Class<?>) source);
}
if (source instanceof Resource) {
// 从 Resource 加载
return load((Resource) source);
}
if (source instanceof Package) {
// 从 Package 加载
return load((Package) source);
}
if (source instanceof CharSequence) {
// 从 CharSequence 加载
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
接着看 从 Class 加载 load((Class<?>) source)
代码:
private int load(Class<?> source) {
if (isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
load(loader);
}
// 判断核心启动类 是否标注了 @Component 注解
if (isComponent(source)) {
// 将启动类的 BeanDefinition 注册进 beanDefinitionMap 中
this.annotatedReader.register(source);
return 1;
}
return 0;
}
2.3 register 方法实现
引:this.annotatedReader.register(source);
截图:
2.4 registerBean 方法实现
引:registerBean(componentClass);
截图:
2.4 doRegisterBean 方法实现
引:doRegisterBean(beanClass, null, null, null, null);
截图:
代码:
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param beanClass the class of the bean
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider, if any,
* in addition to qualifiers at the bean class level
* @param supplier a callback for creating an instance of the bean
* (may be {@code null})
* @param customizers one or more callbacks for customizing the factory's
* {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
// BeanDefinitionHolder 就是针对 BeanDefinition 的一个持有对象,里面有两个内容,分别是 BeanDefinition 和 BeanName
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
2.5 接着 registerBeanDefinition 方法实现
引:BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
截图:
代码:
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName(); //获取 beanName
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 注册 BeanDefinition
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
2.6 接着看 registerBeanDefinition 方法实现
引:registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
截图:
这是一个接口,接着看其具体实现类:
找到其默认实现类 DefaultListableBeanFactory
这就回到第一步的 registerBeanDefinition 方法
截图:
代码:
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//在注册 bd 的时候判断该名字有没有被注册
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//该名字已经被注册
//spring 默认支持覆盖 bd,但是 spring 会输入一些日志
//1、两个 bd 相同的情况下
//2、两个 bd 不同的情况 role 不同
//3、两个 bd 不相同但是 role 相同
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
//优先级
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断我们的 spring 容器是否开启实例化 bean了
//如果为null,set 为空,没有开始就创建 bean 不会进入 if
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
//一个 map 一个 list ,list里面方法的 map 的 key,也就是 beanName
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//如果注册了 beanDefinition 的名字和手工注册的 bd 集合当中某个相同则删除手动注册的 beanName
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
//判断注册的 bd 以及 beanName 是否存在
if (existingDefinition != null || containsSingleton(beanName)) {
//清除 allBeanNameByType
//把单例池当中的 bean 也 remove
resetBeanDefinition(beanName);
}
}
总结:prepareContext()的主要工作: 1、向context完成一些属性的设置 2、将主类生成实例对象,存到容器中。
参考文章:SpringBoot源码深度剖析——@SpringBootApplication注解和new SpringApplication().run()方法深度解密_生活,没那么矫情的博客-CSDN博客