32 SpringBoot启动原理与流程

版权声明:看什么?6,你和我,走一波! https://blog.csdn.net/qq_31323797/article/details/84958593

1 启动原理

1.1 入口(Springboot27Application.java)

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

1.2 开始启动(SpringBootApplication.java)

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class[]{primarySource}, args);
}
	
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	/*
		项目启动分为2步
			1: new SpringApplication(primarySources)
				创建SpringApplication对象
				
			2: .run(args)
				运行run方法
	*/
	return (new SpringApplication(primarySources)).run(args);
}
1.2.1 创建SpringApplication对象
public SpringApplication(Class... primarySources) {
	this((ResourceLoader)null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
	this.sources = new LinkedHashSet();
	this.bannerMode = Mode.CONSOLE;
	this.logStartupInfo = true;
	this.addCommandLineProperties = true;
	this.addConversionService = true;
	this.headless = true;
	this.registerShutdownHook = true;
	this.additionalProfiles = new HashSet();
	this.isCustomEnvironment = false;
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
	
	// 1 获取应用类型
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	
	// 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
	this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
	
	// 3 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
	
	// 4 从多个配置类中找到有main方法的主配置类
	this.mainApplicationClass = this.deduceMainApplicationClass();
}
1.2.1.1 获取应用类型
static WebApplicationType deduceFromClasspath() {
	// 根据容器中指定的类是否存在来判断应用类型
	if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
		return REACTIVE;
	} else {
		String[] var0 = SERVLET_INDICATOR_CLASSES;
		int var1 = var0.length;

		for(int var2 = 0; var2 < var1; ++var2) {
			String className = var0[var2];
			if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
				return NONE;
			}
		}

		return SERVLET;
	}
}
1.2.1.2 配置的所有ApplicationContextInitializer
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = this.getClassLoader();
	Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	......
	return instances;
}
  • SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
	String factoryClassName = factoryClass.getName();
	return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
	if (result != null) {
		return result;
	} else {
		try {
			// 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
			// eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
			# Application Context Initializers
			org.springframework.context.ApplicationContextInitializer=\
			org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
			org.springframework.boot.context.ContextIdApplicationContextInitializer,\
			org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
			org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
			
			/*
				从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer
				
				eg: org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar!/META-INF/spring.factories
					# Application Context Initializers
					org.springframework.context.ApplicationContextInitializer=\
					org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
					org.springframework.boot.context.ContextIdApplicationContextInitializer,\
					org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
					org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
			*/
			Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
			......
			// 保存起来
			cache.put(classLoader, result);
			return result;
		} catch (IOException var13) {
			throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
		}
	}
}

所有的ApplicationContextInitializer

1.2.1.3 配置的所有ApplicationListener
原理与 1.2.1.2 中一致

所有ApplicationListener

1.2.1.4 配置的所有ApplicationListener
1.2.2 运行run方法
public ConfigurableApplicationContext run(String... args) {
	// 1 监听
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	
	// 2 声明一个空的IOC容器
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
	this.configureHeadlessProperty();
	
	// 3 获取SpringApplicationRunListeners: 底层使用getSpringFactoriesInstances()方法获取,原理与1.2.1.2中一致(从类路径下META-INF/spring.factories)
	SpringApplicationRunListeners listeners = this.getRunListeners(args);
	
	// 4 回调所有的获取SpringApplicationRunListener.starting()方法
	listeners.starting();

	Collection exceptionReporters;
	try {
		// 5 封装命令行参数(项目启动时,可以在命令行中指定参数)
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		
		//6 准备环境,创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
		ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
		
		this.configureIgnoreBeanInfo(environment);
		
		// 7 打印banner图标
		Banner printedBanner = this.printBanner(environment);
		
		// 8 创建ApplicationContext : 创建IOC容器
		context = this.createApplicationContext();
		exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
		
		/*
			9 准备上下文环境 
				将配置好的环境放入IOC容器
				
				applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法(1.2.1.2)
				
				回调所有的SpringApplicationRunListener的contextPrepared();
				
				prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded()
		*/
		this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		
	
        // 10 刷新容器 : ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
		// 扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
		this.refreshContext(context);
		
		this.afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
		}

		listeners.started(context);
		
		/*
			11 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
				ApplicationRunner先回调,CommandLineRunner再回调
		*/
		this.callRunners(context, applicationArguments);
	} catch (Throwable var10) {
		this.handleRunFailure(context, var10, exceptionReporters, listeners);
		throw new IllegalStateException(var10);
	}

	try {
		listeners.running(context);
		
		//整个SpringBoot应用启动完成以后返回启动的ioc容器;
		return context;
	} catch (Throwable var9) {
		this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
		throw new IllegalStateException(var9);
	}
}
1.2.2.1 获取SpringApplicationRunListeners

3 获取SpringApplicationRunListeners

1.2.2.2 准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
	// 判断环境是否存在,存在及获取,不存在及创建
	ConfigurableEnvironment environment = this.getOrCreateEnvironment();
	
	// 配置环境
	this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
	
	// 创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
	listeners.environmentPrepared((ConfigurableEnvironment)environment);
	
	this.bindToSpringApplication((ConfigurableEnvironment)environment);
	if (!this.isCustomEnvironment) {
		environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
	}

	ConfigurationPropertySources.attach((Environment)environment);
	return (ConfigurableEnvironment)environment;
}
1.2.2.3 准备上下文环境
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	// 将配置好的环境放入IOC容器
	context.setEnvironment(environment);
	
	// 后置处理
	this.postProcessApplicationContext(context);
	
	// 回调之前保存的所有的ApplicationContextInitializer的initialize方法
	this.applyInitializers(context);
	
	// 回调所有的SpringApplicationRunListener的contextPrepared(1.2.1.3)
	listeners.contextPrepared(context);
	
	// 日志记录
	if (this.logStartupInfo) {
		this.logStartupInfo(context.getParent() == null);
		this.logStartupProfileInfo(context);
	}

	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	
	// 将命令行参数注册进来
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	
	// 将banner注册
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}

	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}

	Set<Object> sources = this.getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	this.load(context, sources.toArray(new Object[0]));
	
	// 回调所有的SpringApplicationRunListener的contextLoaded()
	listeners.contextLoaded(context);
}

猜你喜欢

转载自blog.csdn.net/qq_31323797/article/details/84958593