--------------------------基与spring-boot-2.0.0.BUILD-SNAPSHOT--------------------------------------
正常来说,我们一个spring boot 入门程序会大概这么写
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
这一节我们来分析一下SpringApplication.run()都做了什么
-----------------------------------------------------------------------------------------------------------
首先run重载了几个方法,这个就是我们调用run方法的入口
public static ConfigurableApplicationContext run(Class primarySource,
String... args) {
//在这里new一个Class数组,primarySource在本例子=App.class
return run(new Class[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class[] primarySources,
String[] args) {
//此处先根据Class数组new一个SpringApplication(),然后执行run方法
return new SpringApplication(primarySources).run(args);
}
剩下的run方法等下再看,先看new SpringApplication()的过程
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
//此处的resourceLoader=null
this.resourceLoader = resourceLoader;
//断言sources不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
//将class数组构建成一个LinkedHashSet
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//web application 可能的枚举类型
this.webApplicationType = deduceWebApplication(); -- >1
//实例化所有可用的ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));-- >2
//实例化所有可用的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));-- >3
this.mainApplicationClass = deduceMainApplicationClass();-- >4
}
// 1< -- 推断可能的webApplication类型,并返回对应的枚举值
private WebApplicationType deduceWebApplication() {
//REACTIVE_WEB_ENVIRONMENT_CLASS=org.springframework.web.reactive.DispatcherHandler
//MVC_WEB_ENVIRONMENT_CLASS=org.springframework.web.servlet.DispatcherServlet
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
//application应该运行在reactive web application且应该启动一个嵌入的reactive web server
return WebApplicationType.REACTIVE;
}
//private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
//"org.springframework.web.context.ConfigurableWebApplicationContext" }
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
//application不应该不应该运行一个web application且不启动嵌入的web server
return WebApplicationType.NONE;
}
}
//application应该运行在一个基于servlet的web application且应该启动一个嵌入的web server
return WebApplicationType.SERVLET;
}
//这里我们再说一下ClassUtils.isPresent();
//主要是判断className在classLoader下是否存在,if classLoader为null
//then classLoader=Thread.currentThread().getClassLoader()
//if classLoader还是为null then classLoader=ClassUtils.class.getClassLoader()
//if classLoader还是为null then classLoader=ClassLoader.getSystemClassLoader()
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
} catch (Throwable var3) {
return false;
}
}
//这里是forName的代码,有兴趣的自己瞧瞧
public static Class forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
Class clazz = resolvePrimitiveClassName(name);
if(clazz == null) {
clazz = (Class)commonClassCache.get(name);
}
if(clazz != null) {
return clazz;
} else {
Class ex;
String clToUse1;
if(name.endsWith("[]")) {
clToUse1 = name.substring(0, name.length() - "[]".length());
ex = forName(clToUse1, classLoader);
return Array.newInstance(ex, 0).getClass();
} else if(name.startsWith("[L") && name.endsWith(";")) {
clToUse1 = name.substring("[L".length(), name.length() - 1);
ex = forName(clToUse1, classLoader);
return Array.newInstance(ex, 0).getClass();
} else if(name.startsWith("[")) {
clToUse1 = name.substring("[".length());
ex = forName(clToUse1, classLoader);
return Array.newInstance(ex, 0).getClass();
} else {
ClassLoader clToUse = classLoader;
if(classLoader == null) {
clToUse = getDefaultClassLoader();
}
try {
return clToUse != null?clToUse.loadClass(name):Class.forName(name);
} catch (ClassNotFoundException var9) {
int lastDotIndex = name.lastIndexOf(46);
if(lastDotIndex != -1) {
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
try {
return clToUse != null?clToUse.loadClass(innerClassName):Class.forName(innerClassName);
} catch (ClassNotFoundException var8) {
;
}
}
throw var9;
}
}
}
}
//2< -- 原文:Sets the {@link ApplicationContextInitializer} that will be applied to the Spring{@link ApplicationContext} public void setInitializers( Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<>(); this.initializers.addAll(initializers); } //2<-- 3<-- 是2 也是 3 //2 type=ApplicationContextInitializer.class //3 type=ApplicationListener.class private Collection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class[] {}); } private Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) { //获取当前上下文classLoader ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //使用名称并确保唯一以防止重复 Set names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // loadName List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//createInstance //获取到可以实例化的根据OrderComparator排序 AnnotationAwareOrderComparator.sort(instances); return instances; } /**************************************loadName***********************************************/ //SpringFactoriesLoader.loadFactoryNames //factoryClass=ApplicationContextInitializer.class public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); //getOrDefault如果factoryClassName==null?Collections.emptyList():factoryClassName return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } //获取spring工厂 //private static final Map<ClassLoader,MultiValueMap<String,String>> cache = new ConcurrentReferenceHashMap(); //用这个map做缓存 以classLoader为key,LinkedMultiValueMap为value private static Map> loadSpringFactories(ClassLoader classLoader) { MultiValueMap result = (MultiValueMap)cache.get(classLoader); if(result != null) { return result; } else { try { //?查找所有给定名称的资源(spring.factories):从用来加载类的搜索路径中查找所有具有指定名称的资源(spring.factories) Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result1 = new LinkedMultiValueMap(); //spring.factories-----由于太多 就不贴出来了,以 key=\value,\value2的方式存储 while(ex.hasMoreElements()) { URL url = (URL)ex.nextElement(); UrlResource resource = new UrlResource(url); //当成Properties来获取 Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry entry = (Entry)var6.next(); //这里的commaDelimitedListToStringArray 是把以,分割的字符串转成string数组 List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue())); result1.addAll((String)entry.getKey(), factoryClassNames); } } //放入cache中 cache.put(classLoader, result1); return result1; } catch (IOException var9) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9); } } } default V getOrDefault(Object key, V defaultValue) { V v; return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue; } /**************************************loadName***********************************************/ /***********************************createInstance*******************************************/ //获取能够被实例化的class列表 // type=ApplicationContextInitializer.class // parameterTypes=new Class[]{} // classLoader=Thread.currentThread().getContextClassLoader() //args=null //names=获取到的linkedHashSet()集合 private List createSpringFactoriesInstances(Class type, Class[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List instances = new ArrayList<>(names.size()); for (String name : names) { try { Class instanceClass = ClassUtils.forName(name, classLoader); //断言是否是type的subClass Assert.isAssignable(type, instanceClass); Constructor constructor = instanceClass .getDeclaredConstructor(parameterTypes); //实例化class T instance = (T) BeanUtils.instantiateClass(constructor, args); //加到list中 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }//4< -- private Class<?> deduceMainApplicationClass() { try { //StackTraceElement用栈的方式保存了方法的调用信息 //获取当前调用栈,匹配main并找到所在的类,并将clone()后的类返回 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; }
到这里 ConfigurableApplicationContext就构造完成了
接下来看看它的run方法
public ConfigurableApplicationContext run(String... args) {
//StopWatch是spring的一个util工具,主要是用来记录程序的运行时间
StopWatch stopWatch = new StopWatch();
//记录程序的开始时间
stopWatch.start();
ConfigurableApplicationContext context = null;
//SpringBootExceptionReporter用来支持报告关于启动的错误
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();//-- >1
SpringApplicationRunListeners listeners = getRunListeners(args);//-- >2
//开启监听器 此处启动的是spring.factories的org.springframework.boot.context.event.EventPublishingRunListener
//可以通过查看源码知道这个类都做了什么,就是在run方法的不同阶段发送不同的事件
//这里用到一个观察者模式
listeners.starting();
try {
//应用参数:这里我的args是null
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);//-- >3
configureIgnoreBeanInfo(environment);//-- >4
//打印Banner 这里分OFF LOG CONSOLE 分别是不打印、Log、System,out
Banner printedBanner = printBanner(environment);
//创建ApplicationContext、
context = createApplicationContext();// -- > 5
//实例化SpringBootExceptionReporter.class 并指定ConfigurableApplicationContext参数的构造器
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);// -- > 6
refreshContext(context);
afterRefresh(context, applicationArguments);
//停止监听
listeners.finished(context, null);
//停止并记录时间
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
}
//1 < --
private void configureHeadlessProperty() {
//设置指定键值对的系统属性
//SYSTEM_PROPERTY_JAVA_AWT_HEADLESS="java_awt_headless",默认值为"true"
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
//2 < --
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
//实例化可用的SpringApplicationRunListener(指定了types的构造器)
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
//3 < --
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建并配置环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (isWebEnvironment(environment)
&& this.webApplicationType == WebApplicationType.NONE) {
environment = convertToStandardEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
//返回对应的环境 刚才已经初始化过webApplicationType
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webApplicationType == WebApplicationType.SERVLET) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
//4 < --
//从这里我们可以看出spring boot的环境主要是property与profiles
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
//判断defaultProperties(map)是否为空
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
//MutablePropertySources内部维护一个list<PropertySource<?>>集合,先removeIfPresent()然后把defaultProperties加到最后
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
//判断addCommandLineProperties ==true 和 args的长度 此处我们的args=0
if (this.addCommandLineProperties && args.length > 0) {
//name=commandLineArgs
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {//如果改列表中包括了
PropertySource source = sources.get(name);//获取到这个PropertySource资源
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(
name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
//如果不存在就加到最前面,这样子可以起到一个作用是
//如果通过main()做的配置 会最优执行
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
//spring.active.profile的值
environment.getActiveProfiles(); // ensure they are initialized
// But these ones should go first (last wins in a property key clash)
Set profiles = new LinkedHashSet<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
//将additionalProfiles和getActiveProfiles的值加到一起
//设置到环境中
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
//5 < -- 创建ApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
//DEFAULT_WEB_CONTEXT_CLASS="org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
break;
//DEFAULT_REACTIVE_WEB_CONTEXT_CLASS="org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext"
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
//DEFAULT_CONTEXT_CLASS=org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext"
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
//6 < --
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
至此:run方法结束