关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

newSpringApplication

发布时间:2023-06-26 13:00:17

SpringBoot启动流程之(构造SpringApplication.class)

  • new SpringApplication()流程图如下

1.程序入口

//复合注解,内部包含了组件扫描以及自动配置 @SpringBootApplication public class DemoApplication {  public static void main(String[] args) {  //引导启动应用  SpringApplication.run(DemoApplication.class, args);  } }

   

2.内部应用启动SpringApplication#Run方法

 

public static ConfigurableApplicationContext run(Class[]primarySources,String[]args){  //首先new了一个SpringApplication,并且把当前启动类作为入参  return new SpringApplication(primarySources).run(args);  }

   

3.第一大步SpringApplication的构造方法

public SpringApplication(ResourceLoader resourceLoader,Class...primarySources){  this.resourceLoader=resourceLoader;  //引导类不能为空  Assert.notNull(primarySources,"PrimarySources must not be null");  this.primarySources=new LinkedHashSet<>(Arrays.asList(primarySources));  //获取当前应用的类型,分为三种NONE,SERVLET,REACTIVE;  this.webApplicationType=WebApplicationType.deduceFromClasspath();  //设置了Spring应用上下文初始化的实例  // 获取spring.factories中前缀为org.springframework.context.ApplicationContextInitializer的集合  //并且将ApplicationContextInitializer应用于Spring ApplicationContext  setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));  //设置了Spring上下文所需要的侦听者  //获取spring.factories中前缀为org.springframework.context.ApplicationListener的集合  setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));  this.mainApplicationClass=deduceMainApplicationClass();  }

   

3.1. 判断应用类型

 

static WebApplicationType deduceFromClasspath(){  //根据应用下是否存在某个特定的类来确定确定应用类型  if(ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS,null)&&!ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS,null)  &&!ClassUtils.isPresent(JERSEY_INDICATOR_CLASS,null)){  //响应式web容器  return WebApplicationType.REACTIVE;  }  for(String className:SERVLET_INDICATOR_CLASSES){  if(!ClassUtils.isPresent(className,null)){  //非web容器  return WebApplicationType.NONE;  }  }  //servletWeb容器  return WebApplicationType.SERVLET;  }

   

  • 总结
    • 根据是否存在某个特定类,来判定当前应用类型
    • 应用类型分为三种
      • ServletWeb服务器
      • 响应式Web服务器
      • 非Web服务器

3.2.实例化ApplicationContextInitializer

privateCollectiongetSpringFactoriesInstances(Classtype,Class[]parameterTypes,Object...args){  ClassLoader classLoader=getClassLoader();  //根据条件加载spring.factories的实现类,并进行Set集合去重(条件:ApplicationContextInitializer)  Setnames=new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type,classLoader));  //通过反射创建符合ApplicationContextInitializer接口的对应实例  Listinstances=createSpringFactoriesInstances(type,parameterTypes,classLoader,args,names);  //实例集合排序(留个疑惑)  AnnotationAwareOrderComparator.sort(instances);  return instances;  }

   

3.2.1 SpringFactoriesLoader#loadFactoryNames

 

public static ListloadFactoryNames(Class factoryType,@Nullable ClassLoader classLoader){  //获取传入参数的转化为全限定类名,用作筛选map集合的value  String factoryTypeName=factoryType.getName();  //loadSpringFactories(classLoader)加载内路径下的META-INF/spring.factories并转化为Map  //map集合的getOrDefault方法用key进行对比,如果存在key则返回对应的value,否则返回默认值  return loadSpringFactories(classLoader).getOrDefault(factoryTypeName,Collections.emptyList());  }

   

3.2.2 SpringFactoriesLoader#loadSpringFactories
  • (一定要笑着看完加载META-INF/spring.factories的流程)

 

private static Map<String, List>loadSpringFactories(@Nullable ClassLoader classLoader){  //从缓存获取当前classLoader的map集合  MultiValueMapresult=cache.get(classLoader);  //如果存在,则使用当前classLoader的map集合  if(result!=null){  return result;  }  //否则,加载META-INF/spring.factories下的元素,并转化为map  try{  // 判断当前classLoader是否为空,如果不为空,则使用当前classLoader获取绝对路径信息,否则使用系统classLoader获取信息  Enumerationurls=(classLoader!=null?  classLoader.getResources(FACTORIES_RESOURCE_LOCATION):  ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));  result=new LinkedMultiValueMap<>();  while(urls.hasMoreElements()){  URL url=urls.nextElement();  UrlResource resource=new UrlResource(url);  //将对应url的键值对信息转为properties格式  Properties properties=PropertiesLoaderUtils.loadProperties(resource);  //遍历properties的key  for(Map.Entry entry:properties.entrySet()){  String factoryTypeName=((String)entry.getKey()).trim();  //遍历对应key的value,并进行格式转化  for(String factoryImplementationName:StringUtils.commaDelimitedListToStringArray((String)entry.getValue())){  //转入对应map  result.add(factoryTypeName,factoryImplementationName.trim());  }  }  }  //map存储配置信息,方便下次取用  cache.put(classLoader,result);  return result;  }  catch(IOException ex){  throw new IllegalArgumentException("Unable to load factories from location ["+  FACTORIES_RESOURCE_LOCATION+"]",ex);  }  }

   

  • 这就是前面提到的META-INF/spring.factories文件的庐山真面目(PS:源文件篇幅太长,我删了点东西️ )
    • spring.factories这个文件声明了一系列bean的全类名(因为项目就不可能扫描全部电脑文件,而一些依赖不存在于项目能够扫描的范围,所有需要一个文件来保存它们的信息) ,要说SpringBoot最核心的东东是啥,我觉得是这个东西。
    • SpringBoot最核心的便是自动装配,而自动装配依赖于META-INF/spring.factories下声明的依赖
    • META-INF/spring.factories不止一个,在不同的包下面有多个(具体加载了哪个包下面的,需要自己DEBUG查看)
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition,\ org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\

   


3.2.3 (开始真正的创建对象喽!)createSpringFactoriesInstances(type,parameterTypes,classLoader,args,names)

privateListcreateSpringFactoriesInstances(Classtype,Class[]parameterTypes,  ClassLoader classLoader,Object[]args,Setnames){  Listinstances=new ArrayList<>(names.size());  //遍历前面加载的全限定类集合  for(String name:names){  try{  Class instanceClass=ClassUtils.forName(name,classLoader);  Assert.isAssignable(type,instanceClass);  //通过反射构造特定对象,parameterTypes为参数  Constructor constructor=instanceClass.getDeclaredConstructor(parameterTypes);  T instance=(T)BeanUtils.instantiateClass(constructor,args);  instances.add(instance);  }  catch(Throwable ex){  throw new IllegalArgumentException("Cannot instantiate "+type+" : "+name,ex);  }  }  //将构造的对象返回  return instances;  }

   


  • 好了,到此为止,SpringBoot的初始构造方法的流程基本上都在这了,接下来会缕一缕new SpringApplication(primarySources).run(args)中的run(args)那部分了️
    • 其实SpringApplication的构造方法,主要就是完成了这几件事
      1. 判断了当前应用的类型
      2. 加载、实例化了SpringApplication的Initializers所需要的类,并且set进SpringApplication
      3. 加载、实例化了SpringApplication的Listeners所需要的类,并且set进SpringApplication
      4. 通过运行栈获取了main方法的定义类(这个获取在后面没啥子大事要它干)

PS:前面讲了new SpringApplication,而入口函数就是由new SpringApplication以及run()组成的,下面将来讲一下run()的逻辑️


/template/Home/leiyu/PC/Static