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