1、spring boot 入口类
package com.vesus.springboothelloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootHelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootHelloworldApplication.class, args);
}
}
2、查看注解@SpringBootApplication配置
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
去掉元注解,剩下三个注解@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan下面我们进入到SpringBootConfiguration类。
2.1、查看@SpringBootConfiguration注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
可以看到这个注解实际上和@Configuration有相同的作用.
2.2、@ComponentScan
顾名思义,这个注解完成的是自动扫描的功能,相当于Spring XML配置文件中的,默认扫描@ComponentScan注解所在类的同级类和同级目录下的所有类.
<context:component-scan>
2.3、@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
- 入口方法
3.1 SpringApplication的实例化
SpringApplication.run(SpringbootHelloworldApplication.class, args);
相应实现:
//实现方法
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的实例(new SpringApplication),然后运行它的run方法:
public SpringApplication(Object... sources) {
//调用初始化方法
initialize(sources);
}
SpringApplication的构造函数会调用initialize方法进行初始化
private void initialize(Object[] sources) {
//判断参数是否存在,存在添加至sources中,该属性是一个LinkedHashSet类型
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断是否为web程序,主要判断类中是否包含(“javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext)这两个类
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
1、首先,会把sources参数添加到SpringApplication对象的sources属性,该属性是一个LinkedHashSet类型
private final Set<Object> sources = new LinkedHashSet<Object>();
接下来的调用了deduceWebEnvironment方法,判断是否为web程序,主要判断类中是否包含(“javax.servlet.Servlet”,
"org.springframework.web.context.ConfigurableWebApplicationContext)这两个类
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
2、接下来初始化ApplicationContextInitializer
在classpath下的JAR文件中包含的/META/spring.factories文件里找到对应的属性,然后实例化并排序,设置到SpringApplication对象的initializers属性,该属性是一个ArrayList类型
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 在classpath下的JAR文件中包含的/META/spring.factories文件里找到对应的属性
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//实例化并排序,设置到SpringApplication对象的initializers属性
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
取出的属性值为:
0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
3 = "org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer"
4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"
3、初始化监听器ApplicationListener
在classpath下的JAR文件中包含的/META/spring.factories文件里找到org.springframework.context.ApplicationListener对应的属性,然后实例化并排序,设置到SpringApplication对象的listeners属性,该属性是一个ArrayList类型
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;
}
取出的属性值为:
0 = "org.springframework.boot.ClearCachesApplicationListener"
1 = "org.springframework.boot.builder.ParentContextCloserApplicationListener"
2 = "org.springframework.boot.context.FileEncodingApplicationListener"
3 = "org.springframework.boot.context.config.AnsiOutputApplicationListener"
4 = "org.springframework.boot.context.config.ConfigFileApplicationListener"
5 = "org.springframework.boot.context.config.DelegatingApplicationListener"
6 = "org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"
7 = "org.springframework.boot.logging.ClasspathLoggingApplicationListener"
8 = "org.springframework.boot.logging.LoggingApplicationListener"
9 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer"
4、最后调用deduceMainApplicationClass方法找到main函数所在的类,实现的方式是获取当前方法调用栈,找到main函数的类,并设置到SpringApplication对象的mainApplicationClass属性,该属性是一个Class类型
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;
}