淘先锋技术网

首页 1 2 3 4 5 6 7

SpringBoot之SpringApplication

启动类

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

源码

  • 初始化SpringApplication对象,并run
/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified source using default settings.
 * @param source the source to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Object source, String... args) {
	return run(new Object[] { source }, args);
}
/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified sources using default settings and user supplied arguments.
 * @param sources the sources to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
	return new SpringApplication(sources).run(args);
}

初始化

private final Set<Object> sources = new LinkedHashSet<Object>();
private boolean webEnvironment;
private Class<?> mainApplicationClass;
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };
/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * 
 * 创建一个新的{@link SpringApplication}实例。
 * 应用程序上下文将从指定的源加载bean(参见{@link SpringApplication class-level}文档了解详细信息)。可以在调用之前定制实例
 * 
 * {@link #run(String...)}.
 * @param sources the bean sources
 * @see #run(Object, String[])
 * @see #SpringApplication(ResourceLoader, Object...)
 */
public SpringApplication(Object... sources) {
	initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
	//1,添加资源
	if (sources != null && sources.length > 0) {
		this.sources.addAll(Arrays.asList(sources));
	}
	//2,记录是否可以加载Servlet,ConfigurableWebApplicationContext
	this.webEnvironment = deduceWebEnvironment();
	//加载所有的ApplicationContextInitializer子类
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
	//加载所有的ApplicationListener子类
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	//获取启动类
	this.mainApplicationClass = deduceMainApplicationClass();
}
//验证Servlet,ConfigurableWebApplicationContext是否可以加载到
private boolean deduceWebEnvironment() {
	for (String className : WEB_ENVIRONMENT_CLASSES) {
		//判断改路径地址的类是否可以加载到,加载到返回true
		if (!ClassUtils.isPresent(className, null)) {
			return false;
		}
	}
	return true;
}
//根据class,找到该接口下的所有子类
//获取所有的META-INF/spring.factories文件
//获取文件中配置的子类,并创建给对象
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) {
	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<String>(
			SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
			classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}
//获取启动类
private Class<?> deduceMainApplicationClass() {
	try {
		//创建一个异常,获取StackTraceElement数组,这个很有意思
		StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
		for (StackTraceElement stackTraceElement : stackTrace) {
			//根据main方法获取启动类
			if ("main".equals(stackTraceElement.getMethodName())) {
				return Class.forName(stackTraceElement.getClassName());
			}
		}
	}
	catch (ClassNotFoundException ex) {
		// Swallow and continue
	}
	return null;
}

解析

  • sources保存TestApplication
  • 记录是否可以加载Servlet,ConfigurableWebApplicationContext
  • 加载所有的ApplicationContextInitializer子类
  • 加载所有的ApplicationListener子类
  • 获取启动类

run

/**
 * Run the Spring application, creating and refreshing a new
 * 运行Spring应用程序,创建并刷新一个新的应用程序
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
	//打开计时器
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	//上下文局部变量定义
	ConfigurableApplicationContext context = null;
	FailureAnalyzers analyzers = null;
	//设置java.awt.headless的系统属性
	configureHeadlessProperty();
	//获取启动时监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	//启动各个监听器
	listeners.starting();
	try {
		//运行参数的设置
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
		//准备环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		Banner printedBanner = printBanner(environment);
		//根据webEnvironment值,创建上下文或默认上下文
		context = createApplicationContext();
		analyzers = new FailureAnalyzers(context);
		//准备上下文,本文重点
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
		//实例化单例,如果失败关闭所有单例
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		//通知所有监听器,上下文初始化结束
		listeners.finished(context, null);
		//关闭计时器
		stopWatch.stop();
		//打印启动时间【Started TestApplication in 46.973 seconds (JVM running for 48.238)】
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
		return context;
	}
	catch (Throwable ex) {
		handleRunFailure(context, listeners, analyzers, ex);
		throw new IllegalStateException(ex);
	}
}