1.入口:
@SpringBootApplication
public class BusApplication {
public static void main(String[] args) {
SpringApplication.run(BusApplication.class, args);
}
}
通过调用
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) 静态方法
主要执行线索大的方向有两条:
(new SpringApplication(primarySources)).run(args);
以上代码拆分为两步走:
1. SpringApplication 对象的创建
new SpringApplication(primarySources)
2.调用SpringApplication对象的run方法
后续会根据这两方面分析。
2. SpringApplication 对象的创建
主要代码流程如下:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//推断应用类型
this.webApplicationType = this.deduceWebApplicationType();
//setInitializers初始化模块,加载ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//加载监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 推断mian方法所在类【此地有彩蛋----通过】后续会分析 通过new RuntimeException()获取到栈信息
this.mainApplicationClass = this.deduceMainApplicationClass();
}
2.1 推断应用类型分析
this.webApplicationType = this.deduceWebApplicationType();
枚举类定义一共三种类型:
public enum WebApplicationType {
NONE,
SERVLET,
REACTIVE;
private WebApplicationType() {
}
}
此方法中重点调用了
ClassUtils.isPresent(String className, @Nullable ClassLoader classLoader)
后续会专门分析,此处不表,此类做了大量优化
2.2 setInitializers初始化模块,加载ApplicationContextInitializer
重点分析:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
阅读Spring Boot代码会发现大量调用此方法,这个就是Spring 借鉴 JAVA的SPI机制
SPI后续会专门分析
getSpringFactoriesInstances(ApplicationContextInitializer.class)
具体步骤分析:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//1获取类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
重点分析:
SpringFactoriesLoader.loadFactoryNames(type, classLoader)
源码如下:
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); ArrayList result = new ArrayList(); while(urls.hasMoreElements()) { URL 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 var8) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8); } }
这个才是重点;
META-INF/spring.factories
扫描jar包下面的META-INF下面的spring.factories文件
循环处理spring.factories文件
1.读取spring.factories文件内容
2.将文件转化为Properties对象 (此对象和我们熟知的MAP差不多都是键值对)
3.根据接口的class名称 获取实现该接口的对象名称字符串
4.根据 逗号分隔字符串 ,然后转化为ArrayList
开始创建对象实例:
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
源码如下:
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { // 1.根据接口实现的对象列表的大小创建List集合 List<T> instances = new ArrayList<T>(names.size()); //2.开始循环处理 for (String name : names) { try { //3.获取某个实现类的 Class对象 Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); //4.根据Class对象,根据参数类型,获取响应构造函数 Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes); //5.通过构造函数,反射获取对象实例 T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
上述的过程在Spring框架中有众多的应用。
例如:
ApplicationContextInitializer.class
ApplicationListener.class
均是采用如上方法实例化的;