SpringBoot运⾏原理
SpringBoot 运⾏原理
⾃从写了第⼀个 SpringBoot 程序后摸了⼏天鱼,现在回来研究⼀下 SpringBoot 的运⾏原理!
1. 依赖⽂件pom
之前 SpringBoot 创建的是⼀个 Maven 项⽬,所以对应的配置⽂件 l 中肯定包含了项⽬需要的所有依赖。点进 l 查看,发现只有⼏个启动器依赖,不过可以看到这个项⽬存在⼀个⽗项⽬ spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
点进这个⽗项⽬查看,发现没有 dependencies 部分,只有⽂件导出和插件等 build 配置;但它⼜依赖了⼀个⽗项⽬ spring-boot-dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.4</version>
</parent>
再次点进这个⽗项⽬,看到了2000多⾏的依赖配置,这才是项⽬需要的 jar 包依赖所在!其中,给许多依赖都配置了对应的版本,如
<aspectj.version>1.9.7</aspectj.version>
引⽤时直接引⽤配置的版本号
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
所以我们在引⼊⼀些依赖的时候,不需要指定版本号,就是因为在依赖配置中已经选好了!但引⼊依赖配置中没有的依赖时,仍需指定其版本号。
2. 启动器
回到最初的 pom ⽂件上,可以看到 SpringBoot 启动器的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
启动器的作⽤就是加载模块的运⾏环境,如上⾯的 spring-boot-starter 就加载了 SpringBoot 的运⾏环境,spring-boot-starter-web 就加载了 Web 模块的运⾏环境!
SpringBoot 把模块的运⾏环境都提取为启动器,需要运⾏什么模块只需引⼊对应的启动器,就可以引⼊需要的所有依赖了!
3. 主启动类注解
创建完 SpringBoot 项⽬时,可以看到项⽬⾃带了⼀个带有 main ⽅法的类,即主启动类
spring怎么读取properties@SpringBootApplication
public class SpringBoot01HelloApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloApplication.class, args);
}
}
先从注解分析⼀下主启动类是个什么东西!
3.1 @SpringBootApplication
@SpringBootApplication:标注在类上表明这个类是 SpringBoot 的主启动类,SpringBoot 就会运⾏这个类的 main ⽅法来启动 SpringBoot 应⽤。
点进这个注解,⼜可以看到许多其他注解,其中有三个重要的
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication
将主启动类上的 @SpringBootApplication 注解换成这三个注解,程序依然能够运⾏;不过为了⽅便,还是直接⽤ @SpringBootApplication 就⾏了!
其中,@ComponentScan 在 Spring 中已经见过了,它是⼀个⾮常重要的注解,作⽤为⾃动扫描并加载符合条件的组件( Bean )。
3.2 @SpringBootConfiguration
@SpringBootConfiguration:标注在类上表明这个类是 SpringBoot 的配置类。
点进这个注解,可以看到 @Configuration 注解
@Configuration
public @interface SpringBootConfiguration
说明标注了该注解的类就是⼀个配置类,对应 Spring 中的 XML 配置⽂件!
继续深⼊,⼜看到了 @Component 注解
@Component
public @interface Configuration
这就说明,主启动类也是 Spring 中的组件,它负责的就是启动应⽤!
3.3 @EnableAutoConfiguration
@EnableAutoConfiguration:标注在类上表明开启⾃动配置功能,将所有符合条件的 @Configuration 配置都创建为 bean,并加载到当前 SpringBoot 的 IoC 容器中。
点进这个注解,可以看到
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration
点进其中的 @AutoConfigurationPackage 注解,可以看到 @import 注解
@Import({Registrar.class})
public @interface AutoConfigurationPackage
即 @AutoConfigurationPackage 注解的功能是由 @Import注解实现的,主要作⽤就是将主启动类所在包及所有⼦包下的组件到扫描到 Spring 的 IoC 容器中,这也是为什么新建的包要和主启动类同级的原因了!
另⼀个注解 @Import(AutoConfigurationImportSelector.class) 才是最关键的。通过AutoConfigurationImportSelector 类,@EnableAutoConfiguration 可以让 SpringBoot 应⽤将所有符合条件的 @Configuration 配置都创建为 bean,并加载到当前 SpringBoot 的 IoC 容器中。
在 AutoConfigurationImportSelector 类中,可以看到获取候选配置的⽅法 getCandidateConfigurations
// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 这⾥返回的就是⼀开始看到的启动⾃动导⼊配置⽂件的注解类 EnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader.SpringFactoriesLoaderFactoryClass(), BeanClassLoad er());
e sure that file is correct.");
return configurations;
}
这个⽅法调⽤了 SpringFactoriesLoader 类的 loadFactoryNames ⽅法以获取配置类
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
...
String factoryTypeName = Name();
// ⼜调⽤了 loadSpringFactories ⽅法
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, ptyList());
}
上⾯⼜再次调⽤了同⼀个类下的 loadSpringFactories ⽅法,这个⽅法有点长,不过主要做了两件事
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
// 获取名为 "META-INF/spring.factories" 的资源
// ...
// 将读取到的资源遍历,封装为⼀个 properties
// ...
}
到现在我也看晕了,不过可以看到⼀个出现多次的名字 META-INF/spring.factories,搜索这个⽂件,发现它在 spring-boot-autoconfigure-2.5.4.jar ⾥⾯,看来和⾃动装配关系匪浅!
看看它都有什么东西
到这估计就有点恍然⼤悟了,spring.factories 中包含了所有 SpringBoot 要⾃动装配的配置类,通过⾃动读取它们并装配,才实现了 SpringBoot 不需要我们进⾏什么配置也能直
接运⾏的效果!
例如,在⾥⾯到个熟悉的关于 WebMVC 的配置
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
点进这个配置类,可以看到熟悉的前缀后缀、静态资源过滤等 WebMVC 的配置,即完成了之前使⽤ SpringMVC 时的配置(我也晕了可能是这样吧)。
⼩结
SpringBoot 在启动的时候从类路径下的 META-INF/spring.factories ⽂件中获取 @EnableAutoConfiguration 要⾃动装配的配置类,将这些配置类作为 bean 导⼊ IoC 容器中,⾃动配置就⽣效了。
不是所有的 AutoConfiguration ⾃动配置类都会被装配,还要判断是否符合装配的条件 @(⾃动配置类的注解),只有符合条件这个类才会被装配!
在容器中导⼊的 AutoConfiguration ⾃动配置类就是当前运⾏场景需要的所有组件,且已经配置完成,省去了我们⼿动进⾏配置的⼯作!
4. 主启动类⽅法
主启动类中只有⼀个 main ⽅法和⼀句话
@SpringBootApplication
public class SpringBoot01HelloApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloApplication.class, args);
}
}
运⾏主启动类的 main ⽅法,开启的是整个 SpringBoot 的服务!核⼼就是 SpringApplication.run ⽅法,它包含两部分
SpringApplication 对象的实例化
run ⽅法的执⾏
查看 SpringApplication 类的构造器,可以发现它主要做了四件事
判断应⽤类型是普通项⽬还是 Web 项⽬
this.webApplicationType = WebApplicationType.deduceFromClasspath();
加载所有可⽤的初始化器,设置到 initializers 属性中( List<ApplicationContextInitializer<?>> initializers )
this.SpringFactoriesInstances(ApplicationContextInitializer.class));
加载所有可⽤的程序,设置到 listeners 属性中( List<ApplicationListener<?>> listeners )
this.SpringFactoriesInstances(ApplicationListener.class));
推断并设置 main ⽅法的定义类,到运⾏的主类
this.mainApplicationClass = this.deduceMainApplicationClass();
⾄于 run ⽅法的执⾏流程以后再说吧,我已经要吐了。
5. 总结
简单了解⼀下 SpringBoot 的运⾏原理······只能说是硬着头⽪看,看不明⽩也没办法。
⼀点点理解:SpringBoot 通过启动器的依赖,判断要⾃动装配哪些配置类,这些 Spring 配置类采⽤的是 JavaConfig 的⽅式,即使⽤ @Configuration 注解进⾏配置,进⾏了许多默认的配置,即所谓的约定;如不⼿动进⾏配置的更改,则会按照默认的配置运⾏,避免了重复配置的过程,即约定⼤于配置。
希望看出来的⼀点点理解是正确的吧,这种东西就应该放到最后 !

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。