spring boot 启动过程理解

基本类

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);
}	

流程分析

  1. spring boot启动
@SpringBootApplication
public class Blog2Application {

    public static void main(String[] args) {
        SpringApplication.run(Blog2Application.class, args);
    }

}
  1. 初始化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();
}
  1. 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根据方法参数类型来自动监听相应事件的发布

具体解析过程

总结

  1. SpringApplication.run(Class clz)方法首先会创建SpringApplication对象,从META-INF/spring.factories中搜索初始器和监听器
  2. SpringApplicationRunListener用于在IOC容器启动过程中发布对应事件给监听器处理
  3. Banner默认加载 “gif”, “jpg”, “png” "txt"结尾的banner文件资源
  4. 在prepareContext时加载传入的clz到beanFactory中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值