Spring Boot 源码解析-SpringApplication

文章目录

我们生成一个spring boot 项目时,会自带一个启动类. 代码如下:

@SpringBootApplication
public class AdminBootstrap {
	public static void main(String[] args) {
		 new SpringApplicationBuilder(AdminBootstrap.class).web(true).run(args); 
	}

}   

就是这么简单的代码,构成了spring boot的世界. 那么代码中只有一个@SpringBootApplication 注解 和 调用了SpringApplication#run方法.那么我们先来解析SpringApplication的run方法.

SpringApplication初始化

  1. 首先调用SpringApplication.initialize
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void initialize(Object[] sources) {
		//1.如果sources长度大于0的话,加入到SpringApplication的sources中,该sources是一个LinkedHashSet.
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		//2.调用deduceWebEnvironment方法判断是否是web环境
		this.webEnvironment = deduceWebEnvironment();
		//3.设置initializers.
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		//4.设置Listeners.
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//5.设置mainApplicationClass.
		this.mainApplicationClass = deduceMainApplicationClass();
	}

  • deduceWebEnvironment发现会调用ClassUtils类的isPresent方法,检查classpath中是否存在javax.servlet.Servlet类和org.springframework.web.context.ConfigurableWebApplicationContext类,如果存在的话,返回true.否则返回false.

	private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };
	private boolean deduceWebEnvironment() {
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return false;
			}
		}
		return true;
	}
  • 在设置Initializers时首先调用getSpringFactoriesInstances方法加载ApplicationContextInitializer.然后直接赋值给initializers.代码如下:
	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		//1.首先获得ClassLoader
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		//2.调用SpringFactoriesLoader#loadFactoryNames进行加载,然后放入到LinkedHashSet进行去重.
		
		Set<String> names = new LinkedHashSet<String>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//3.调用createSpringFactoriesInstances进行初始化
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		//4.对实例进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
  • 使用给定的类加载器从“META-INF / spring.factories”加载给定类型的工厂实现的完全限定类名。
	public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		//1.获得factoryClassName,对于当前来说factoryClassName =org.springframework.context.ApplicationContextInitializer.
		String factoryClassName = factoryClass.getName();
		try {
			//2.通过传入的classLoader加载META-INF/spring.factories文件.
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			//3.通过调用PropertiesLoaderUtils#loadProperties将其转为Properties.
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				String factoryClassNames = properties.getProperty(factoryClassName);
				
			//4.获得factoryClassName对应的值进行返回. 
			result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
					"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}
  • 对于当前来说,在spring-boot/META-INF/spring.factories中.org.springframework.context.ApplicationContextInitializer值如下:
# 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.context.embedded.ServerPortInfoApplicationContextInitializer
  • createSpringFactoriesInstances遍历传入的names,也就是之前通过SpringFactoriesLoader加载的类名.通过遍历,依次调用其构造器进行初始化.加入到instances.然后进行返回.
	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<T>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

对于当前场景来说:
ConfigurationWarningsApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer初始化没有做任何事.

ContextIdApplicationContextInitializer在初始化时.会获得spring boot的应用名.搜索路径如下:

spring.application.name
vcap.application.name
spring.config.name
如果都没有配置的话,返回application
	private static final String NAME_PATTERN = "${spring.application.name:${vcap.application.name:${spring.config.name:application}}}";
	
	public ContextIdApplicationContextInitializer() {
		this(NAME_PATTERN);
	}

	public ContextIdApplicationContextInitializer(String name) {
		this.name = name;
	}
  • 设置SpringApplication#setListeners时,还是同样的套路.调用getSpringFactoriesInstances加载META-INF/spring.factories中配置的org.springframework.context.ApplicationListener.
    对于当前来说.加载的类如下:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

这些类在构造器中都没有做任何事.

  • 调用SpringApplication#deduceMainApplicationClass方法.获得应用的启动类.该方法通过获取当前方法调用栈,找到main函数的类.代码如下:
	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

SpringApplication的run方法

	public ConfigurableApplicationContext run(String... args) {
		//1.初始化StopWatch,调用其start方法开始计时.
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		//2.调用configureHeadlessProperty设置系统属性java.awt.headless,这里设置为true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能
		configureHeadlessProperty();
		//3.调用SpringApplicationRunListeners#starting
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			//4.创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数.调用prepareEnvironment方法.
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			//5.打印banner
			Banner printedBanner = printBanner(environment);
			//6.创建SpringBoot上下文
			context = createApplicationContext();
			//7.初始化FailureAnalyzers
			analyzers = new FailureAnalyzers(context);
			//8.调用prepareContext
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			//9.调用AbstractApplicationContext#refresh方法,并注册钩子
			refreshContext(context);
			//10.在容器完成刷新后,依次调用注册的Runners
			afterRefresh(context, applicationArguments);
			//11.调用SpringApplicationRunListeners#finished
			listeners.finished(context, null);
			//12.停止计时
			stopWatch.stop();
			//13.初始化过程中出现异常时调用handleRunFailure进行处理,然后抛出IllegalStateException异常.
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/sid1109217623/article/details/83894677
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞