文章目录
基本类
SpringApplication
用于启动Spring应用程序
public class SpringApplication {
// 项目类型
private WebApplicationType webApplicationType;
// 监听器
private List<ApplicationListener<?>> listeners;
// 主类资源
private Set<Class<?>> primarySources;
// main启动类
private Class<?> mainApplicationClass;
// 启动图形
private Banner banner;
}
AnnotationConfigApplicationContext
基于Java的注解配置类加载Spring的应用上下文
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
// 用于对注解Bean类的解析
private final AnnotatedBeanDefinitionReader reader;
// 用于在ClassPath路径上解析Bean类的扫描器
private final ClassPathBeanDefinitionScanner scanner;
}
AnnotationMetadata
表示对特定类的注释的抽象访问
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
// 合并的注解
private final MergedAnnotations mergedAnnotations;
private final boolean nestedAnnotationsAsMap;
@Nullable当前类上的注解元素
private Set<String> annotationTypes;
}
ConfigurationClass
用来表示@Configuration注解的类
final class ConfigurationClass {
// 注解元数据
private final AnnotationMetadata metadata;
// 通过metadata解析,含有注解存在类的全限制名称
private final Resource resource;
@Nullable
private String beanName
// 在配置类通过@Import导入的类
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
}
流程分析
- spring boot启动
@SpringBootApplication
public class Blog2Application {
public static void main(String[] args) {
SpringApplication.run(Blog2Application.class, args);
}
}
- 初始化SpringApplication,根据类路径是否包含类来设置web项目类型,
从META-INF/spring.factories中
获得初始器实例(在applicationContext调用refresh之前设置一些配置如端口号)、获得监听器。
// 调用run方法传入主要资源
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);
}
// 创建SpringApplication实例
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 这里资源加载器为空
this.resourceLoader = resourceLoader;
// primarySource必须传入
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// NONE(非Web项目)、SERVLET(Servlet Web项目)、REACTIVE(响应式Web项目)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从META-INF/spring.factories中获得应用上下文初始器实例
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 初始化监听实例
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 从堆栈中找到main启动类
this.mainApplicationClass = deduceMainApplicationClass();
}
- run方法启动创建ConfigurableApplicationContext
- 容器启动计时
- java.awt.headless属性设置,表示运行程序缺少外设模式
- 创建Spring运行监听器,并发布ApplicationStartingEvent事件
- 通过启动参数和监听ApplicationEnvironmentPreparedEvent事件完成环境资源的配置
- banner打印,banner.jpg、banner.txt
- 创建IOC容器,根据WebApplicationType创建不同类型的ApplicationContext(默认AnnotationConfigApplicationContext),创建@Configuration、@AutoWired、JSR-250、JPA、事件监听和事件监听工厂处理器
- 从META-INF/spring.factories中获得异常报告器
- 准备上下文
- 刷新上下文
- 刷新后回调,无具体实现
- 计时完成
- 发布ApplicationStartedEvent事件
- 调用Runner,ApplicationRunner和CommandLineRunner的run方法
- 发布ApplicationReadyEvent事件
public ConfigurableApplicationContext run(String... args) {
// 容器启动计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// java.awt.headless属性设置,默认为true
configureHeadlessProperty();
// 创建Spring运行监听器,并发布ApplicationStartingEvent事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 初始化启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 通过启动参数和监听ApplicationEnvironmentPreparedEvent事件完成环境资源的配置
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// banner打印
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);
// 调用Runner
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;
}
3.1 创建应用上下文,根据webApplicationType类型创建不同的IOC容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
···异常
}
// 实例化对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
3.2 准备应用上下文
- 配置环境变量,设置设置beanName生成器、资源加载器和类型转换
- 调用初始器的initialize方法
- ApplicationContextInitializedEvent事件发布
- 添加单例bean,springApplicationArguments和springBootBanner
- 参数设置,是否重复覆盖和懒加载
- 调用register方法注册配置类
- 发布ApplicationPreparedEvent事件
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境
context.setEnvironment(environment);
// 设置beanName生成器、资源加载器和类型转换
postProcessApplicationContext(context);
// 调用初始器的initialize方法
applyInitializers(context);
// 发布ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 添加单例bean,springApplicationArguments、springBootBanner
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
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());
}
// 调用register方法注册配置类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 发布ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
3.3 刷新应用上下文,详见
private void refreshContext(ConfigurableApplicationContext context) {
// 刷新容器
refresh((ApplicationContext) context);
if (this.registerShutdownHook) {
try {
// 添加jvm钩子函数来销毁IOC容器,发布ContextClosedEvent事件
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
3.4 环境属性获取
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 根据WebApplicationType创建不同类型的Environment对象,此步骤会添加系统Properties和系统Environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 添加SpringApplication的defaultProperties属性值和命令行参数属性值
// 配置当前哪个环境变量起效
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 添加configurationProperties属性(包含当前所有配置属性)
ConfigurationPropertySources.attach(environment);
// 发布ApplicationEnvironmentPreparedEvent事件
// META-INF/spring.factories中的ConfigFileApplicationListener监听实现添加random属性和application.properties文件
// 依次加载默认路径下拓展名为:.properties .xml .yml .yaml的application文件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
注解
ConfigurationClassPostProcessor处理@Configuration
- @Configuration指示一个类声明一个或多个@Bean方法,并且可以由Spring容器在运行时为这些Bean生成Bean定义和服务请求
- @Bean指示方法生成一个由Spring容器管理的bean
- @Import指示要导入的一个或多个Configuration类,能够填@Configuration、ImportSelector、ImportBeanDefinitionRegistrar或@Component类型
- @ImportResource用于导入资源文件如部分XML
- @PropertySource设置.properties配置文件的路径(file: classpath:)
- @Component注解的类作为bean注入到IOC容器中
- @ComponentScan用于@Configuration类的组件扫描指令,扫描指定包(basePackages),未指定则扫描当前注解配置的包,使用includeFilters和excludeFilters指定过滤和包含的类型
- @Filter用于过滤指定类,type(ANNOTATION注解规则、ASSIGNABLE_TYPE给定的类型、ASPECTJ、REGEX正则、CUSTOM自定义),value指定过滤规则下的表达式
ConfigurationClassPostProcessor继承BeanDefinitionRegistryPostProcessor接口,刷新IOC容器时调用postProcessBeanDefinitionRegistry方法
遍历BeanDefinitionNames获得所有配置的类并设置对应属性FULL(@Configuration根据是否含有proxyBeanMethods属性)或LITE(@Bean,@Import,@ImportResource,@Component,@ComponentScan)
获得beanName的生成器,为所有注解的类生成BeanDifinition时自动生成名字(AnnotationBeanNameGenerator,如不指定名称则使用小写类名作为beanName
)
创建ConfigurationClassParser来解析注解配置类,解析结果为ConfigurationClass具体解析过程
AutowiredAnnotationBeanPostProcessor处理@Autowired
- @Autowired作用于构造器,字段,方法、参数和注解,默认通过类型查找自动装配,可以通过@Qualifier实现以名称注入
- @Inject默认以类型注入,可以配置@Name来实现以名称注入
- @Value将外部的值动态注入到Bean中
CommonAnnotationBeanPostProcessor处理通用注解
- @Resource,类似@AutoWired完成数据的自动注入,有两个属性name和type,如果设置了以此为准,否则默认byName
- @PostConstruct,与xml中init-method作用相同,在bean实例化属性配置完成后调用
- @PreDestroy,与xml中destroy-method作用相同,在bean销毁时调用
- @WebServiceRef,定义对Web服务的引用
- @EJB,注入EJB对象
EventListenerMethodProcessor处理
- @EventListener根据方法参数类型来自动监听相应事件的发布
总结
- SpringApplication.run(Class clz)方法首先会创建SpringApplication对象,从META-INF/spring.factories中搜索初始器和监听器
- SpringApplicationRunListener用于在IOC容器启动过程中发布对应事件给监听器处理
- Banner默认加载 “gif”, “jpg”, “png” "txt"结尾的banner文件资源
- 在prepareContext时加载传入的clz到beanFactory中