SpringBoot 源码分析

2021/8/16 20:06:34

本文主要是介绍SpringBoot 源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

传统的spring框架实现web服务需要导入很多依赖,并编写对应的xml配置文件,而springboot可以进行依赖管理和自动配置

1. 依赖管理:以web项目为例,有两个核心依赖

  • 为什么导入dependency时不需要指定版本?
  • spring-boot-starter-parent父依赖启动器的主要作用是进行版本统一管理,那么项目运行的jar包从何而来?
    • spring-boot-starter-parent依赖:作为springboot项目的统一父项目依赖管理,并将当前项目版本号统一为2.2.2RELEASE,该版本号可以很具实际开发需求修改
<!-- Spring Boot父项目依赖管理 -->
 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
      • spring-bootstarter-parent的底层有一个父依赖spring-boot-dependencies
      <!-- 对依赖版本进行了管理-->
      <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-dependencies</artifactId>
          <version>2.5.3</version>
        </parent>
      
      <!--对项目编码,java版本以及资源进行管理和过滤-->
      <properties>
          <java.version>1.8</java.version>
          <resource.delimiter>@</resource.delimiter>
          <maven.compiler.source>${java.version}</maven.compiler.source>
          <maven.compiler.target>${java.version}</maven.compiler.target>
          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        </properties>
      • spring-boot-dependencies底层源文件通过标签对一些常用技术框架的依赖文件进行了统一版本号管理,例如activemq、spring、tomcat等,都有与Spring Boot 2.2.2版本相匹配的版本
      • 如果pom.xml引入的依赖文件不是 spring-boot-starter-parent管理的,那么在pom.xml引入依赖文件时需要使用标签制定依赖文件的版本号
    • spring-boot-starter-web:spring-boot-starter-web依赖启动器的主要作用是提供Web开发场景所需的底层所有依赖
<!-- web 依赖--> 
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
      • 在pom.xml中引入spring-boot-starter-web依赖启动器时,就可以实现Web场景开发,而不要额外导入Tomcat服务器以及其他Web依赖文件等
      • 这些依赖文件的版本号由parent父依赖进行统一管理
  • starter依赖启动器:包含了相关组件的一系列依赖文件,依赖启动器适用于不同的场景开发,使用时只需要在pox.xml文件中导入对应的依赖启动器即可
    • https://github.com/spring-projects/spring-boot/tree/v2.1.0.RELEASE/spring-boot-project/spring-boot-starters
    • https://mvnrepository.com/search?q=starter
  • Spring Boot官方并不是针对所有场景开发的技术框架都提供了场景启动器,例如数据库操作框架MyBatis、阿里巴巴的Druid数据源等,Spring Boot官方就没有提供对应的依赖启动器。
    • 为了充分利用Spring Boot框架的优势,在Spring Boot官方没有整合这些技术框架的情况下,MyBatis、Druid等技术框架所在的开发团队主动与Spring Boot框架进行了整合,实现了各自的依赖启动器,例如
      mybatis-spring-boot-starter、druid-spring-boot-starter等。
    • 我们在pom.xml文件中引入这些第三方的依赖启动器时,切记要配置对应的版本号

2. 自动配置:自动导入组件的相关配置

  • Spring Boot到底是如何进行自动配置的,都把哪些组件进行了自动配置?
    • Spring Boot应用的启动入口是@SpringBootApplication注解标注类中的main()方法
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
      • @SpringBootApplication : SpringBoot 应用标注在某个类上说明这个类是 SpringBoot 的主配置类,运行这个类的main方法启动springboot应用
    • 在SpringBootApplication 注解下

 

@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举中
@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时
@Documented //表示注解可以记录在javadoc中
@Inherited //表示可以被子类继承该注解
@SpringBootConfiguration // 标明该类为配置类
@EnableAutoConfiguration // 启动自动配置功能
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes =
AutoConfigurationExcludeFilter.class) }) //对组件进行过滤和扫描
public @interface SpringBootApplication {

// 根据class来排除特定的类,使其不能加入spring容器,传入参数value类型是class类型。
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};

// 根据classname 来排除特定的类,使其不能加入spring容器,传入参数value类型是class的全类名字符串数组。
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};

// 指定扫描包,参数是包名的字符串数组。
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

// 扫描特定的包,参数类似是Class类型数组。 @AliasFor(annotation = ComponentScan.class, attribute ="basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }

 

  • @SpringBootConfiguration注解: SpringBoot 的配置类,标注在某个类上,表示这是一个 SpringBoot的配置类。
    • 从上述源码可以看出,@SpringBootConfiguration注解内部有一个核心注解@Configuration,该注解是Spring框架提供的,表示当前类为一个配置类(XML配置文件的注解表现形式),并可以被组件扫描器扫描。
    • @SpringBootConfiguration注解的作用与@Configuration注解相同,都是标识一个可以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot进行了重新封装命名而已
  • @EnableAutoConfiguration注解:开启自动配置功能
    • 是一个组合注解, Spring 中有很多以 Enable 开头的注解,其作用就是借助 @Import来收集并注册特定场景相关的 Bean ,并加载到 IOC 容器
    • @EnableAutoConfiguration就是借助@Import来收集所有符合自动配置条件的bean定义,并加载到IoC容器。
    • @AutoConfigurationPackage注解:由@Import注解实现的,它是spring框架的底层注解,它的作用就是给容器中导入某个组件类,例如@Import(AutoConfigurationPackages.Registrar.class),它就是将Registrar这个组件类导入到容器中,registerBeanDefinitions()方法是导入组件类的具体实现
    • @AutoConfigurationPackage注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring容器中
    • 因此 在定义项目包结构时,要求定义的包结构非常规范,项目主程序启动类要定义在最外层的根目录位置,然后在根目录位置内部建立子包和类进行业务开发
    • @Import({AutoConfigurationImportSelector.class})注解
      • 将 AutoConfigurationImportSelector 这个类导入到 Spring 容器中,AutoConfigurationImportSelector 可以帮助 Springboot 应用将所有符合条件的 @Configuration
        配置都加载到当前 SpringBoot 创建并使用的 IOC 容器( ApplicationContext )中。
      • 继续研究AutoConfigurationImportSelector这个类,通过源码分析这个类中是通过selectImports这个方法告诉springboot都需要导入那些组件
      • 深入getCandidateConfigurations方法:这个方法中有一个重要方法loadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件的名字
      • 继续点开loadFactory方法会去读取一个 spring.factories 的文件,读取不到会表这个错误,我们继续根据会看到,最终路径的长这样,而这个是spring提供的一个工具类 其实是去加载一个外部的文件,而这文件是在 @EnableAutoConfiguration就是从classpath中搜寻META-INF/spring.factories配置文件,并将其中
        org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(JavaRefletion)实例化为对应的标注了@Configuration的JavaConfig形式的配置类,并加载到IOC容器中 以刚刚的项目为例,在项目中加入了Web环境依赖启动器,对应的WebMvcAutoConfiguration自动配置类就会生效,打开该自动配置类会发现,在该配置类中通过全注解配置类的方式对Spring MVC运行所需环境进行了默认配置,包括默认前缀、默认后缀、视图解析器、MVC校验器等。而这些自动配置类的本质是传统Spring MVC框架中对应的XML配置文件,只不过在Spring Boot中以自动配置类的形式进行了预先配置。因此,在Spring Boot项目中加入相关依赖启动器后,基本上不需要任何配置就可以运行程序,当然,我们也可以对这些自动配置类中默认的配置进行更改
  • 总结springboot底层实现自动配置的步骤是
    • springboot应用启动
    • @SpringBootApplication起作用
    • @EnableAutoConfiguration
    • @AutoConfigurationPackage:这个组合注解主要是@Import(AutoConfigurationPackages.Registrar.class),它通过将Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理的
      容器中
    • @Import(AutoConfigurationImportSelector.class):它通过将AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类作用是通过selectImports方法执行的过程
      中,会使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的METAINF/spring.factories进行加载,实现将配置类信息交给SpringFactory加载器进行一系列的容器创
      建过程
  •  @ComponentScan注解:具体扫描的包的根路径由Spring Boot项目主程序启动类所在包位置决定,在扫描过程中由前面介绍的@AutoConfigurationPackage注解进行解析,从而得到Spring Boot项目主
    程序启动类所在包的具体位置



这篇关于SpringBoot 源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程