应用上下文
创建SpringBootExceptionReporter
java
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
SpringBootExceptionReporter
是 Spring Boot 框架中的一个组件,它负责处理并报告在 Spring Boot 应用启动过程中发生的异常。这个类不是直接暴露给应用开发者使用的,而是 Spring Boot 内部用来提供友好的异常报告和诊断信息。
当 Spring Boot 应用启动失败时,SpringBootExceptionReporter
会捕获异常,并尝试以易于理解的方式输出异常信息和可能的原因。这通常包括堆栈跟踪、错误描述以及可能的解决方案或建议。
应用上下文预处理
应用上下文设置环境
java
context.setEnvironment(environment);
java
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
...
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
名词解释
AnnotatedBeanDefinitionReader
AnnotatedBeanDefinitionReader
是 Spring 框架中的一个类,它用于从注解的类、接口、方法或字段中读取 Bean 定义,并将其注册到 BeanDefinitionRegistry
中。这允许 Spring 容器管理和自动装配这些组件。
当你在 Spring 配置中使用 @Component
, @Service
, @Repository
, @Controller
等注解时,AnnotatedBeanDefinitionReader
会扫描这些注解,并创建相应的 BeanDefinition
对象。这些对象描述了 Spring 容器中 Bean 的元数据,如类名、生命周期回调、属性注入等。
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner
是 Spring 框架中的一个类,它用于扫描类路径(classpath)上的特定包,以查找带有特定注解的类,并将这些类注册为 Spring 容器中的 Bean 定义。这是 Spring 的组件扫描(Component Scanning)功能的核心部分,它使得开发者能够使用注解来自动发现和配置 Bean,而不是通过传统的 XML 配置方式。
ClassPathBeanDefinitionScanner
通常与 @ComponentScan
注解一起使用,后者在 Spring Boot 应用中尤为常见。当 Spring 容器启动时,它会根据 @ComponentScan
注解指定的包路径来扫描类,并使用 ClassPathBeanDefinitionScanner
来查找带有 @Component
、@Service
、@Repository
、@Controller
等注解的类。
二者区别
它们最大的不同在于AnnotatedBeanDefinitionReader
支持注册单个的BeanDefinition
,而ClassPathBeanDefinitionScanner
会一次注册所有扫描到的BeanDefinition
。
容器后处理
java
postProcessApplicationContext(context);
内部实现
java
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
//1、如果当前容器名字的生成器不为空,则往容器工厂中注册容器名字生成器。
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
//2、如果配置的加载器不为空,那么此时需要将配置加载器、类加载器都保存到容器工厂中。
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
//3、如果进行了占位符值的转换,那么此时将相应的转换服务也保存到容器中。
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
加载ApplicationContextInitializers
java
applyInitializers(context);
SPI获取到所有的ApplicationContextInitializers,在这里将被执行。
内部实现
java
protected void applyInitializers(ConfigurableApplicationContext context) {
// 调用每一个实现类的initialize方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
// 将之前获取到的集合进行排序并返回只读集合
public Set<ApplicationContextInitializer<?>> getInitializers() {
return asUnmodifiableOrderedSet(this.initializers);
}
发布ApplicationContextInitializedEvent事件
java
listeners.contextPrepared(context);
记录活动的Profiles日志
java
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
获取beanFactory
java
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
getBeanFactory()
:
getBeanFactory()
是ApplicationContext
接口的一个方法,用于获取底层的BeanFactory
。BeanFactory
是Spring框架中用于管理bean的接口,而ApplicationContext
则是BeanFactory
的子接口,提供了更多的功能,比如支持国际化、事件传播等。ConfigurableListableBeanFactory
:
ConfigurableListableBeanFactory
是BeanFactory
接口的一个实现,它提供了额外的配置能力,并且能够列出容器中定义的bean。它通常用于更高级的配置和编程场景。
将参数对象和banner注册为单例模式
java
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
是否允许覆盖Bean定义
和spring.main.allow-bean-definition-overriding参数有关
java
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
设置懒加载后处理器
java
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
作用是检查当前对象是否启用了懒加载(this.lazyInitialization
是否为true
)。如果启用了懒加载,那么就向Spring的ApplicationContext
中注册一个LazyInitializationBeanFactoryPostProcessor
,以便在后续的bean工厂处理过程中应用懒加载配置。这样做可以使得部分bean在第一次使用时才进行初始化,从而优化应用启动时间和资源使用。
获取Sources并加载
java
// 获取所有的来源文件信息 这里主要指的是启动类。
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 根据相应的sources去进行加载
load(context, sources.toArray(new Object[0]));
// 加载完成后发送相应的事件消息。
listeners.contextLoaded(context);
java
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//创建加载器
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
// 注入bean名字生成器、资源加载器、环境变量信息
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();
}
这里的sources主要指的是Application启动类。上述代码会根据context获取对应的容器注册类,也就是BeanDefinitionRegistry。通俗来说,BeanDefinition Registry就是一个大型的Map结构,其Key是Bean的名字,value是对应BeanDefinition。
BeanDefinition其实就是一个包含所有类信息的定义对象。将其存储在Registry中,是为了方便后续采用反射机制来生成bean,并对相应的Bean进行修改和属性的替换。
java
int load() {
int count = 0;
for (Object source : this.sources) {
count += load(source);
}
return count;
}
首先是会对每个资源都调用相应的load方法。(这里通常只有启动类。)在load方法中,会判断当前资源的类型,根据当前Source类型是类、配置、包还是文本信息,来调用不同的加载方法。
java
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
对类进行加载的方法源代码如下所示:
java
private int load(Class<?> source) {
// 判断当前该资源类是否是采用grovvy定义的资源类
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// 若是,则采用特定的资源类加载器进行加载。
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
// 否则判断当前source是否符合1、非匿名类;2、对Grovvy加载关闭;3、拥有无参构造器
if (isComponent(source)) {
//满足以上三点,才能将相应source进行注册。
this.annotatedReader.register(source);
return 1;
}
return 0;
}
this.annotatedReader.register(source),该方法最终会调用doRegisterBean方法,实现细节如下:
java
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
//新建BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
//获取bean定义的作用范围:如单例、多例等。
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 生成bean的名字信息
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
//设置这个bean的一些属性:如是否需要懒初始化、当前bean是否属于优先加载的等
if (Primary.class == qualifier) {
abd.setPrimary(true);
}else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//紧接着还需要对bean做一些自定义化的处理.
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
// 将对应的beanDefinition及bean名字组装成新的holder进行处理.简单来说就是对内容进行聚合并提供getter、setter方法信息。
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//设置当前bean是否需要被aop进行增强代理
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//最后一步将新的这个bean对象保存到registry中.
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}