spring-boot源码分析(1)--从main方法开始

--------------------------基与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方法结束

猜你喜欢

转载自blog.csdn.net/qq_26093341/article/details/80889916
今日推荐