SpringBoot启动源码详解(⼀)
SpringBoot启动源码详解(⼀)【万字长⽂】
1.⾸先⼤run!
main⽅法作为程序的⼊⼝,执⾏SpringApplication.run(),传⼊参数是启动类的class对象@SpringBootApplication注解
点进来之后,我们发现有两部分,先new,后run,那我们的本⽂的逻辑就⼤致出来了
//创建⼀个新的实例,这个应⽤程序的上下⽂将要从指定的来源加载Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources){
//给变量赋默认值,后续我们都会接触到
this.sources =new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo =true;
this.addCommandLineProperties =true;
this.addConversionService =true;
this.headless =true;
this.additionalProfiles = ptySet();
this.isCustomEnvironment =false;
this.lazyInitialization =false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
//从这⾥开始有意思了,⾸先给资源初始化资源加载器,默认为null
//断⾔,就是资源类不允许为null
//利⽤LinkedHashSet有序和去重,最资源进⾏去重
this.primarySources =new LinkedHashSet(Arrays.asList(primarySources));
//根据jar包推断当前 WEB 应⽤类型,⼀共有三种:NONE,SERVLET,REACTIVE(这个⽅法可以点进去看看)
//根据有⽆javax.servlet.Servlet的jar(servelt)和spring-boot-starter-webflux的jar包,则会启动Reactive模式
//这⾥是SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers =BootstrapRegistryInitializersFromSpringFactories();
//设置应⽤上线⽂初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重(springboot的第⼀个jar包),并进⾏set去重。(⼀共7个)
this.SpringFactoriesInstances(ApplicationContextInitializer.class));
//设置,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重,并进⾏set去重。(⼀共11个)
this.SpringFactoriesInstances(ApplicationListener.class));
//栈操作获取最终实例化对象
this.mainApplicationClass =this.deduceMainApplicationClass();
}
初始化读取的配置⽂件全类名
getSpringFactoriesInstances()⾥⾯create实例的操作的核⼼代码逻辑
private<T> List<T>createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> nam es){
//实例集合,从上⼀层的loader中获取,也就是从上⾯图⽚中的配置⽂件中获取
List<T> instances =new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()){
String name =(();
try{
//变量,然后基本反射操作,构造⽅法获取对象
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = DeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
//添加,然后return
instances.add(instance);
}catch(Throwable var12){
throw new IllegalArgumentException("Cannot instantiate "+ type +" : "+ name, var12);
}
}
return instances;
}
跟踪栈操作
private Class<?>deduceMainApplicationClass(){
try{
StackTraceElement[] stackTrace =(new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 =0; var4 < var3;++var4){
StackTraceElement stackTraceElement = var2[var4];
//栈操作,⽐较相等,反射⽅式创建对象
if("main".MethodName())){
return Class.ClassName());
}
}
}catch(ClassNotFoundException var6){
}
return null;
}
3.正式开始run
public ConfigurableApplicationContext args){
//计时器,监控操作
StopWatch stopWatch =new StopWatch();
stopWatch.start();
// 创建启动上下⽂对象
DefaultBootstrapContext bootstrapContext =ateBootstrapContext();
ConfigurableApplicationContext context =null;
//创建所有spring运⾏并发布应⽤启动事件,简单说的话就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),//并封装进SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说的再简单点,getRunListeners就是准备好了运⾏时EventPublishingRunListener。
SpringApplicationRunListeners listeners =RunListeners(args);
listeners.starting(bootstrapContext,this.mainApplicationClass);
try{
//初始化默认参数
ApplicationArguments applicationArguments =new DefaultApplicationArguments(args);
//准备环境
ConfigurableEnvironment environment =this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//开启忽略
//初始化打印的banner类
Banner printedBanner =this.printBanner(environment);
//创建上下⽂
context =ateApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//准备上下⽂
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//开始刷新
//应⽤上下⽂刷新后置处理,做⼀些扩展功能
this.afterRefresh(context, applicationArguments);
//监控计时停⽌
stopWatch.stop();
//⽇志输⼊类信息,时间等等
if(this.logStartupInfo){
(new StartupInfoLogger(this.mainApplicationClass)).ApplicationLog(), stopWatch);
}
//正式开始监控和执⾏Runner
listeners.started(context);
this.callRunners(context, applicationArguments);
}catch(Throwable var10){
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try{
//发布上下⽂
listeners.running(context);
//⼤⼯告成,开始返回上下⽂
springboot框架是干嘛的return context;
}catch(Throwable var9){
this.handleRunFailure(context, var9,(SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
4.⼀步⼀步来
4.1⾸先进⾏计时监控
public void start(String taskName)throws IllegalStateException {
//创建并启动计时监控类,可以看到记录当前任务的名称,默认是空字符串,
//然后记录当前springboot应⽤启动的开始时间。
if(this.currentTaskName !=null){
throw new IllegalStateException("Can't start StopWatch: it's already running");
}
this.currentTaskName = taskName;
this.startTimeNanos = System.nanoTime();
}
4.2 然后进⾏初始上下⽂和configureHeadlessProperty
private void configureHeadlessProperty(){
System.setProperty("java.awt.headless", Property("java.awt.headless", String(this.headless)));
}
⽤于运⾏headless服务器,进⾏简单的图像处理,多⽤于在缺少显⽰屏、键盘或者⿏标时的系统配置,很多监控⼯具如jconsole 需要将该值设置为true
4.3.然后来到了我们⼀个深⼊点
SpringApplicationRunListeners listeners =RunListeners(args);
listeners.starting(bootstrapContext,this.mainApplicationClass);、
为了防⽌之后看得混乱,我们先理⼀理,现在我们可以知道spring.factory得到了SpringApplicationRunListener的实现类EventPublishingRunListener(有且只要⼀个,这个类很重要,因为事件监听的实现是这个类⾥⾯的⽅法包括
strat,environmentPrepared等等),⽽我们读取spring.factory(⽐如那ApplicationListener的11个实现类,
这些都是new⾥⾯的准备⼯作,我们需要全部串起来)是在SpringApplication这个类⾥⾯,
⽽我们注意我们starting确是在SpringApplicationRunListeners这个类调⽤的,所以对于的实现类是怎么传输过来的呢?
如果可以的话我们可以带着这个疑问来看接下来的源码。因为我们需要关注⼀下各个类之间的关系,
所以我们从最外层⼀步⼀步开始分析
private SpringApplicationRunListeners getRunListeners(String[] args){
Class<?>[] types =new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(SpringFactoriesInstances(SpringApplicationRunListener.class, types,this, args),this.applica tionStartup);
}
我们不点进去都可以看到⼤致逻辑,通过getSpringFactoriesInstances得到⼀个SpringApplicationRunListeners的实例对象
private<T> Collection<T>getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, args){
ClassLoader classLoader =ClassLoader();
Set<String> names =new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances =ateSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
我们可以⼀路点到其中的其中的createSpringFactoriesInstances这个⽅法
private<T> List<T>createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> n ames){
List<T> instances =new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()){
String name =(();
try{
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
//反射操作,我们debug可以发现
Constructor<?> constructor = DeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}catch(Throwable var12){
throw new IllegalArgumentException("Cannot instantiate "+ type +" : "+ name, var12);
}
}
return instances;
}
}
我们可以看到这⾥经典反射构造⽅法构造函数,但是我们debug可以发现构造的正是我们factory⾥⾯的 EventPublishingRunListener这个类。所以我们来看看这个类的构造⽅法
构造⽅法可以看出,将SpringAppliction传过来了,⽽且将其放进了其中的成员变量initalMuticaster,这也为后⾯启动做了铺垫
2.1 listeners.starting(bootstrapContext, this.mainApplicationClass);
到这⾥开始启动了
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论