系列文章目录
1.Springboot2启动过程源码分析-SpringApplication初始化
2.Springboot2启动过程源码分析-SpringApplication#run
3.Springboot2启动过程源码分析-prepareContext方法
4.Springboot2启动过程源码分析-refresh方法
5.Springboot2启动过程源码分析-Bean的实例化
6.Springboot2启动过程源码分析-总结
前言
本节主要对prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner)方法进行研究
prepareContext方法
prepareContext的源码及注释如下:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//1.将ConfigurableEnvironment对象添加到context中
context.setEnvironment(environment);
postProcessApplicationContext(context);
//2.对各种ApplicationContextInitializer进行初始化
applyInitializers(context);
//3.listeners中添加就绪的上下文对象
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//4.这里的beanFactory是DefaultListableBeanFactory的实例
//添加Springboot指定的bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//5.Load the sources,sources集合里面存放的是我们的启动类,其实就是加载SpringApplication的primarySources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//6.Load beans into the application context.加载bean到上下文中
//值得研究一下的load方法
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
这里我们主要看一下load(context, sources.toArray(new Object[0]));
在解读load源码前,先熟悉几个围绕Bean引出的概念
- 1.BeanDefinition: 是一个内部的接口,定义了 Bean 描述的基本规范,是对象在容器中的抽象。
以下是BeanDefinition中的主要方法:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// set/get父definition的名称
void setParentName(@Nullable String parentName);
String getParentName();
// set/get bean definition的类名
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
// set/get bean的范围,如:SCOPE_SINGLETON(单例) SCOPE_PROTOTYPE(多实例)
void setScope(@Nullable String scope);
String getScope();
// set/get 是否延迟初始化
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// set/get 当前bean初始化所依赖的beans的名称
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
// set/get 是否对其他bean是自动装配的候选bean
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// set/get 是否主要的候选bean
void setPrimary(boolean primary);
boolean isPrimary();
// set/get factory bean的名称
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
// set/get 工厂方法的名称
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();
// 返回一个用于新的bean实例上的属性值
MutablePropertyValues getPropertyValues();
}
- 2.BeanDefinitionRegistry:是一个内部的接口, 实现了AliasRegistry接口, 定义了一些对 bean的常用操作。
public interface BeanDefinitionRegistry extends AliasRegistry {
// 常用: 往注册表中注册一个新的 BeanDefinition 实例
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// 移除注册表中已注册的 BeanDefinition 实例
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 从注册中心取得指定的 BeanDefinition 实例
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 判断 BeanDefinition 实例是否在注册表中(是否注册)
boolean containsBeanDefinition(String beanName);
// 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
String[] getBeanDefinitionNames();
// 返回注册表中 BeanDefinition 实例的数量
int getBeanDefinitionCount();
// beanName(标识)是否被占用
boolean isBeanNameInUse(String beanName);
}
- 3. BeanDefinitionLoader:用于加载bean的类
实例化时会初始化以下对象
AnnotatedBeanDefinitionReader: 获取一个或多个带有注解的具体类,解析为BeanDefintion,注册到BeanDefinitionRegistry中
XmlBeanDefinitionReader:获取配置文件中的类,解析为BeanDefintion,注册到BeanDefinitionRegistry中
ClassPathBeanDefinitionScanner: 获取一个或多个包下的带有注解的类,解析为BeanDefintion,注册到BeanDefinitionRegistry中
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 = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
现在,来看一下load方法
- load方法作用: 1)创建BeanDefinitionLoader对象 2)调用BeanDefinitionLoader的load方法完成对sources中的bean进行注册
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//1.创建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);
}
//2.BeanDefinitionLoader执行load
loader.load();
}
其中1处,getBeanDefinitionRegistry(context)会获取BeanDefinitionRegistry的实例, createBeanDefinitionLoader是用来实例化BeanDefinitionLoader
protected BeanDefinitionLoader createBeanDefinitionLoader(
BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
BeanDefinitionLoader的构造方法需要两个参数:
1.registry 是一个ApplicationContent
2.sources .有四种类型分别是class 、Resource 、PackPackage 、CharSequence ,在load(Object source)的时候判断资源的类型 。分别用 AnnotatedBeanDefinitionReader、 XmlBeanDefinitionReader、 BeanDefinitionReader 、ClassPathBeanDefinitionScanner去加载对应的资源放到ApplicationContent中,而每个Reader或Scanner在创建对象时已经通过构造方法中BeannDefinitionRegistry (ApplicationContent)注入了
BeanDefinitionLoader的load方法如下
其中2处,我们不是用Groovy实现的,因此会到第7行的if里面,调用AnnotateBeanDefinitionReader的register方法将我们的启动类注册到容器中。其实AnnotateBeanDefinitionReader的register做了很多事情也是一个重要的方法
private int 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);
load(loader);
}
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
总结
prepareContext围绕着上下文的准备展开,分析了如何将启动类注册到容器中。