SpringBoot启动流程
SpringBoot核心启动类的SpringApplication。从SpringApplication.run()开始先创建SpringApplication对象,并调用该对象的run方法。
public static ConfigurableApplicationContext run(Object source, String... args) { return run(new Object[] { source }, args); } public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return new SpringApplication(sources).run(args);//在这个静态方法中,创建SpringApplication对象,并调用该对象的run方法。 }
构建SpringApplication对象
初始化SpringApplication的source
public SpringApplication(Object... sources) { initialize(sources); } //初始化SpringApplication对象的成员变量sources,webEnvironment,initializers,listeners,mainApplicationClass。 //sources的赋值比较简单,就是我们传给SpringApplication.run方法的参数。 private void initialize(Object[] sources) { // 为成员变量sources赋值 if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
初始化SpringApplication的webEnvironment
private boolean webEnvironment; private static final String[] WEB_ENVIRONMENT_CLASSES = {
"javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext"
}; //可以看到webEnvironment是一个boolean,该成员变量用来表示当前应用程序是不是一个Web应用程序。
//那么怎么决定当前应用程序是否Web应用程序呢,是通过在classpath中查看是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包含的类,
//如果存在那么当前程序即是一个Web应用程序,反之则不然。 private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; }
初始化SpringApplication的initializers
//initializers成员变量,是一个ApplicationContextInitializer类型对象的集合 private List<ApplicationContextInitializer<?>> initializers; public void setInitializers( Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<ApplicationContextInitializer<?>>(); this.initializers.addAll(initializers); } private void initialize(Object[] sources) { ... // 为成员变量initializers赋值 //关键是调用getSpringFactoriesInstances(ApplicationContextInitializer.class),来获取ApplicationContextInitializer类型对象的列表。 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); ... } private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } //首先通过调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,
//然后调用createSpringFactoriesInstances方法根据读取到的名字创建对象。
//最后会将创建好的对象列表排序并返回。 //可以看到,是从一个名字叫spring.factories的资源文件中,读取key为org.springframework.context.ApplicationContextInitializer的value。 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; } public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<T>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass.getConstructor(parameterTypes); T instance = (T) constructor.newInstance(args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; } spring.factories的部分内容如下: # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
初始化SpringApplication的listeners
//listeners成员变量,是一个ApplicationListener<?>类型对象的集合 private List<ApplicationListener<?>> listeners; public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<ApplicationListener<?>>(); this.listeners.addAll(listeners); } private void initialize(Object[] sources) { ... // 为成员变量listeners赋值 //可以看到获取该成员变量内容使用的是跟成员变量initializers一样的方法,
//只不过传入的类型从ApplicationContextInitializer.class变成了ApplicationListener.class。 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); ... } spring.factories中的相关内容: # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener
初始化SpringApplication的mainApplicationClass
private Class<?> mainApplicationClass; private void initialize(Object[] sources) { ... // 为成员变量mainApplicationClass赋值 this.mainApplicationClass = deduceMainApplicationClass(); ... } //通过获取当前调用栈,找到入口方法main所在的类,并将其复制给SpringApplication对象的成员变量mainApplicationClass。 private Class<?> deduceMainApplicationClass() { try { 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; }
启动SpringApplication
经过上面的初始化过程,我们已经有了一个SpringApplication对象,根据SpringApplication类的静态run方法一节中的分析,接下来会调用SpringApplication对象的run方法。我们接下来就分析这个对象的run方法。
//可变个数参数args即是我们整个应用程序的入口main方法的参数 //StopWatch是来自org.springframework.util的工具类,可以用来方便的记录程序的运行时间。 //SpringApplication对象的run方法创建并刷新ApplicationContext public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.started(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); context = createAndRefreshContext(listeners, applicationArguments); 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, ex); throw new IllegalStateException(ex); } }
headless模式
//实际上是就是设置系统属性java.awt.headless,一般运行在没有显示器和键盘的环境时设置为true private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless"; private boolean headless = true; public ConfigurableApplicationContext run(String... args) { ... //设置headless模式 configureHeadlessProperty(); ... } private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty( SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); }
获取listeners
//run方法中,加载了一系列SpringApplicationRunListener对象,
//在创建和更新ApplicationContext方法前后分别调用了listeners对象的started方法和finished方法,
//并在创建和刷新ApplicationContext时,将listeners作为参数传递到了createAndRefreshContext方法中,
//以便在创建和刷新ApplicationContext的不同阶段,调用listeners的相应方法以执行操作。
//所以,所谓的SpringApplicationRunListeners实际上就是在SpringApplication对象的run方法执行的不同阶段,去执行一些操作,并且这些操作是可配置的。 public ConfigurableApplicationContext run(String... args) { ... SpringApplicationRunListeners listeners = getRunListeners(args); listeners.started(); /** * 创建并刷新ApplicationContext * context = createAndRefreshContext(listeners, applicationArguments); **/ listeners.finished(context, null); ... } //同时,可以看到,加载SpringApplicationRunListener时,使用的是跟加载ApplicationContextInitializer和ApplicationListener时一样的方法。
//那么加载了什么,就可以从spring.factories文件中看到了: private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
创建并刷新ApplicationContext
//首先是创建一个DefaultApplicationArguments对象, //之后调用createAndRefreshContext方法创建并刷新一个ApplicationContext, //最后调用afterRefresh方法在刷新之后做一些操作。 public ConfigurableApplicationContext run(String... args) { ... try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); context = createAndRefreshContext(listeners, applicationArguments); afterRefresh(context, applicationArguments); ... } catch (Throwable ex) { handleRunFailure(context, listeners, ex); throw new IllegalStateException(ex); } } //创建一个DefaultApplicationArguments对象 DefaultApplicationArguments(String[] args) { Assert.notNull(args, "Args must not be null"); this.source = new Source(args); this.args = args; } private static class Source extends SimpleCommandLinePropertySource { Source(String[] args) { super(args); } ... } public SimpleCommandLinePropertySource(String... args) { super(new SimpleCommandLineArgsParser().parse(args)); } //createAndRefreshContext方法创建并刷新一个ApplicationContext private ConfigurableEnvironment environment; private boolean webEnvironment; private ConfigurableApplicationContext createAndRefreshContext( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableApplicationContext context; // 创建并配置Environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment);//发送事件 if (isWebEnvironment(environment) && !this.webEnvironment) { environment = convertToStandardEnvironment(environment); } ... return context; } //Spring Application的Environment代表着程序运行的环境, //主要包含了两种信息,一种是profiles,用来描述哪些bean definitions是可用的; //一种是properties,用来描述系统的配置,其来源可能是配置文件、JVM属性文件、操作系统环境变量等等 private ConfigurableEnvironment getOrCreateEnvironment() { //首先要调用getOrCreateEnvironment方法获取一个Environment对象 //执行到此处时,environment成员变量为null,而webEnvironment成员变量的值为true,所以会创建一个StandardServletEnvironment对象并返回 if (this.environment != null) { return this.environment; } if (this.webEnvironment) { return new StandardServletEnvironment(); } return new StandardEnvironment(); } private Map<String, Object> defaultProperties; private boolean addCommandLineProperties = true; private Set<String> additionalProfiles = new HashSet<String>(); //调用configureEnvironment方法来配置上一步获取的Environment对象. protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { //configureEnvironment方法先是调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles configurePropertySources(environment, args); configureProfiles(environment, args); } protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { MutablePropertySources sources = environment.getPropertySources(); //configurePropertySources首先查看SpringApplication对象的成员变量defaultProperties if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { //如果该变量非null且内容非空,则将其加入到Environment的PropertySource列表的最后。 sources.addLast( new MapPropertySource("defaultProperties", this.defaultProperties)); } //然后查看SpringApplication对象的成员变量addCommandLineProperties和main函数的参数args if (this.addCommandLineProperties && args.length > 0) { //如果设置了addCommandLineProperties=true,且args个数大于0 //那么就构造一个由main函数的参数组成的PropertySource放到Environment的PropertySource列表的最前面 //(这就能保证,我们通过main函数的参数来做的配置是最优先的,可以覆盖其他配置) String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; if (sources.contains(name)) { PropertySource<?> source = sources.get(name); CompositePropertySource composite = new CompositePropertySource(name); composite.addPropertySource(new SimpleCommandLinePropertySource( name + "-" + args.hashCode(), args)); composite.addPropertySource(source); sources.replace(name, composite); } else { sources.addFirst(new SimpleCommandLinePropertySource(args)); } } } //configureProfiles首先会读取Properties中key为spring.profiles.active的配置项,配置到Environment //然后再将SpringApplication对象的成员变量additionalProfiles加入到Environment的active profiles配置中 //配置文件里没有spring.profiles.active的配置项 //而SpringApplication对象的成员变量additionalProfiles也是一个空的集合,所以这个函数没有配置任何active profile protected void configureProfiles(ConfigurableEnvironment environment, String[] args) { environment.getActiveProfiles(); // ensure they are initialized // But these ones should go first (last wins in a property key clash) Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(profiles.toArray(new String[profiles.size()])); } //Environment就算是配置完成了. //接下来调用SpringApplicationRunListeners类的对象listeners发布ApplicationEnvironmentPreparedEvent事件.然后listener进行各种响应。
//省略各个listener响应逻辑
//打印banner,printBanner方法中, //首先会调用selectBanner方法得到一个banner对象, //然后判断bannerMode的类型,如果是Banner.Mode.LOG,那么将banner对象转换为字符串,打印一条info日志, //否则的话,调用banner对象的printbanner方法,将banner打印到标准输出System.out。 private Banner banner; private Banner.Mode bannerMode = Banner.Mode.CONSOLE; public static final String BANNER_LOCATION_PROPERTY = "banner.location"; public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt"; private static final Banner DEFAULT_BANNER = new SpringBootBanner(); private ConfigurableApplicationContext createAndRefreshContext( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ... if (this.bannerMode != Banner.Mode.OFF) { printBanner(environment); } ... } protected void printBanner(Environment environment) { Banner selectedBanner = selectBanner(environment); if (this.bannerMode == Banner.Mode.LOG) { try { logger.info(createStringFromBanner(selectedBanner, environment)); } catch (UnsupportedEncodingException ex) { logger.warn("Failed to create String for banner", ex); } } else { selectedBanner.printBanner(environment, this.mainApplicationClass, System.out); } } private Banner selectBanner(Environment environment) { String location = environment.getProperty(BANNER_LOCATION_PROPERTY, BANNER_LOCATION_PROPERTY_VALUE); ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(getClassLoader()); Resource resource = resourceLoader.getResource(location); if (resource.exists()) { return new ResourceBanner(resource); } if (this.banner != null) { return this.banner; } return DEFAULT_BANNER; } private String createStringFromBanner(Banner banner, Environment environment) throws UnsupportedEncodingException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); banner.printBanner(environment, this.mainApplicationClass, new PrintStream(baos)); String charset = environment.getProperty("banner.charset", "UTF-8"); return baos.toString(charset); } //bannerMode是Banner.Mode.Console,而且也不曾提供过banner.txt这样的资源文件。 //所以selectBanner方法中得到到便是默认的banner对象,即SpringBootBanner类的对象: //先打印个Spring的图形,然后打印个Spring Boot的文本,再然后打印一下Spring Boot的版本。 private static final String[] BANNER = { "", " . ____ _ __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /", " =========|_|==============|___/=/_/_/_/" }; private static final String SPRING_BOOT = " :: Spring Boot :: "; private static final int STRAP_LINE_SIZE = 42; @Override public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) { for (String line : BANNER) { printStream.println(line); } String version = SpringBootVersion.getVersion(); version = (version == null ? "" : " (v" + version + ")"); String padding = ""; while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) { padding += " "; } printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version)); printStream.println(); }
//创建ApplicationContext private Class<? extends ConfigurableApplicationContext> applicationContextClass; public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework." + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext"; private ConfigurableApplicationContext createAndRefreshContext( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableApplicationContext context; ... //创建ApplicationContext对象 context = createApplicationContext(); //将我们之前准备好的Environment对象赋值进去 context.setEnvironment(environment); //调用postProcessApplicationContext和applyInitializers做一些处理和初始化的操作 postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } ... return context; } protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { contextClass = Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) //调用BeanUtils的instantiate方法来创建ApplicationContext对象 BeanUtils.instantiate(contextClass); } //通过调用Class对象的newInstance()方法来实例化对象,这等同于直接调用类的空的构造方法 public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException { Assert.notNull(clazz, "Class must not be null"); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { return clazz.newInstance(); } catch (InstantiationException ex) { throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex); } } //构造方法中初始化了两个成员变量, //类型分别为AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner //用以加载使用注解的bean定义。 public AnnotationConfigEmbeddedWebApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } @Override public void setEnvironment(ConfigurableEnvironment environment) { super.setEnvironment(environment); this.reader.setEnvironment(environment); this.scanner.setEnvironment(environment); } //如果成员变量beanNameGenerator不为Null,那么为ApplicationContext对象注册beanNameGenerator bean。 //如果成员变量resourceLoader不为null,则为ApplicationContext对象设置ResourceLoader。 protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.webEnvironment) { if (context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext configurableContext = (ConfigurableWebApplicationContext) context; if (this.beanNameGenerator != null) { configurableContext.getBeanFactory().registerSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } } } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context) .setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context) .setClassLoader(this.resourceLoader.getClassLoader()); } } } protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } } public Set<ApplicationContextInitializer<?>> getInitializers() { return asUnmodifiableOrderedSet(this.initializers); } private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) { List<E> list = new ArrayList<E>(); list.addAll(elements); Collections.sort(list, AnnotationAwareOrderComparator.INSTANCE); return new LinkedHashSet<E>(list); }