--------------------------基與spring-boot-2.0.0.BUILD-SNAPSHOT--------------------------------------java
正常來講,咱們一個spring boot 入門程序會大概這麼寫react
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
這一節咱們來分析一下SpringApplication.run()都作了什麼web
-----------------------------------------------------------------------------------------------------------spring
首先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; }
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方法結束app