Spring boot 启动类:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication该注解源码如下:
主要是引用了其他三个注解@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan暂不作分析。
SpringApplication.run(Application.class, args) run方法的执行
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param sources the sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
先构造一个SpringApplication对象
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param sources the bean sources
* @see #run(Object, String[])
* @see #SpringApplication(ResourceLoader, Object...)
*/
public SpringApplication(Object... sources) {
initialize(sources);
}
然后执行initialize(sources)方法,此处的sources即执行main方法的类实例对象Application.class,initialize(source)源码如下:
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] 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();
}
由以上源码可知主要执行4个方法:
deduceWebEnvironment()
判断当前环境是否是web环境,太简单不做详述。
初始化ApplicationContextInitializer的子类
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
第二个方法setinitializers()之前先执行getSpringFactoriesInstances(ApplicationContextInitializer.class)
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;
}
在方法SpringFactoriesLoader.loadFactoryNames(type,classLoader)中
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);
}
}
即通过在jar中的 META-INF/spring.factories中找到需要初始化的ApplicationContextInitializer的实现类
spring-boot-1.5.9.RELEASE.jar包中的META-INF/spring.factories中ApplicationContextInitializer如下:
# 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.embedded.ServerPortInfoApplicationContextInitializer
将需要初始化的bean名字存放到Set<String> names,接下来就是实例化这些类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);
初始化ApplicationListener的子类
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
方法如3.初始化ApplicationContextInitializer一样的执行过程
deduceMainApplicationClass找到main方法的类实例
this.mainApplicationClass = deduceMainApplicationClass();
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;
}
通过new一个运行时异常,找到栈,在栈信息中遍历得到main方法的主类
至此SpringApplication初始化完成。
开始执行SpringApplication的run方法
第321行代码SpringApplicationRunListeners listeners = getRunlisteners(args)
和new SpringApplication时使用方法一致,在META-INF/spring.factories中得到SpringApplicationRunListener的实现类并且实例化这些对象
第292行执行SpringApplicationRunListener子类的接口中的starting方法
第296行执行prepareEnvironment(listeners,applicationArguments)方法
上图第323行getOrCreateEnvironment()方法new StandardServletEnvironment()类
上图第324行configureEnvironment(environment, applicationArguments.getSourceArgs())
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { configurePropertySources(environment, args); configureProfiles(environment, args); }
configurePropertySources得到new StandardServletEnvironment()构造方法时配置的4个:
servletContextInitParams
servletConfigInitParams
systemProperties
systemEnvironment
configureProfiles(environment, args)得到spring.profiles.active的值
然后执行第325行的springApplicationRunListeners中所有listerns的environmentPrepared()方法
接下来执行run方法的第298行printBanner方法,该方法打印banner信息,即启动时默认的Spring异形文字信息,可以有Image和Textg两种形式默认使用console。通过在properties中配置"banner.location"指定banner.txt的位置来修改文本信息。默认使用 SpringBootBanner类中的信息。如果是图片使用"banner.image.location"指定图片位置,图片只支持gif、jpg、png三种扩展名格式。
第301行执行prepareContext(context, environment, listeners, applicationArguments, printedBanner)方法。上下文环境准备工作。
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 = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); listeners.contextLoaded(context); }
applyInitializers(context)中开始执行ApplicationContextInitializer接口的initialize方法,还有SpringApplicationListener接口中的contextPrepared和contextLoaded方法。
run方法第303行的refreshContext()方法中执行上下文的refresh()方法,即Spring初始化过程中父类AbstractApplicationContext的refresh(),该方法不做详述,太复杂,但与spring一致。
run方法第304行afterRefres()方法启用ApplicationRunner和CommandLineRunner接口中的run方法