SpringBoot自动装配初步浅理解

打印 上一主题 下一主题

主题 829|帖子 829|积分 2487

SpringBoot自动装配原理

Created time: May 15, 2022 6:36 PM
Done: Doing
Last edited time: May 25, 2022 6:13 PM
Tags: Spring, 后端, 总结
0 关于自动配置

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中
  • 在写或者引入一些springboot依赖时,不需要指定版本,因为有这些版本仓库。
启动器
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
复制代码

  • 启动器,SpringBoot的启动场景
  • spring-boot-starter-web 自动导入web环境所有的依赖
  • springboot会将所有的功能场景变成一个一个启动器
主程序
  1. //标注这个类是一个springboot的应用
  2. @SpringBootApplication
  3. public class Springboot01HelloworldApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(Springboot01HelloworldApplication.class, args);
  6.     }
  7. }
复制代码
1 SpringBoot四大核心


  • 四大核心

    • EnableAutoConfiguration自动装配
    • Starter组件,开箱即用
    • Actutor监控
    • SpringBoot Cli为SpringCloud提供SpringBoot命令行功能

1.1 注解

在了解Spring注解之前先了解一些相关注解的知识。
  1. //标注这个类是一个springboot的应用
  2. @SpringBootApplication
  3. //SpringBoot的配置
  4. @SpringBootConfiguration
  5.   @Configuration //Spring配置类
  6.   @Component//本质还是一个Spring组件
  7. //自动配置
  8. @EnableAutoConfiguration
  9.   @AutoConfigurationPackage//自动配置包
  10.   @Import(AutoConfigurationPackages.Registrar.class)//导入选择器包注册
  11.   @Import(AutoConfigurationImportSelector.class)//自动配置导入选择(自动导入包的核心)
  12.   //获取所有的配置
  13.   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
复制代码
  1. //getCandidateConfigurations获取所有的候选配置**
  2. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  3.     List<String> configurations = SpringFactoriesLoader.loadFactoryNames(**getSpringFactoriesLoaderFactoryClass**(),
  4.         getBeanClassLoader());
  5.     Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
  6.         + "are using a custom packaging, make sure that file is correct.");
  7.         return configurations;
  8.         }
  9.         //EnableAutoConfiguration注解被SpringBootApplication继承
  10.         protected Class<?> getSpringFactoriesLoaderFactoryClass() {
  11.           return EnableAutoConfiguration.class;
  12.         }
复制代码
META-INF/spring.factories自动配置的核心文件

  1. //所有的资源加载到类中
  2. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
复制代码
结论
SpringBoot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只要导入对应的start,就有对应的启动器了,有了启动器,自动装配就会生效,然后就配置成功。
2 Enable注解作用

EnableAutoConfiguration 自动装配相关的Eable注解.
开启相关支持,如

  • EnableScheduling ,开启计划任务支持
  • EnableAutoConfiguration ,开启自动装配支持
在EnableAutoConfiguration.java中涉及到Enable开头的注解都会有一个@Import的注解
3 SpringBoot中的自动装配原理

自动装配作为Starter的基础,也是SpringBoot的核心
SpringBoot的自动装配是基于EnableAutoConfiguration 实现的,先了解一下传统意义的自动装配方式。
首先需要了解一些前置关于注解的知识
3.1 Configuration注解

Spring3以后,支持两种配置bean的方式,一种xml文件方式和JavaConfig。
JavaConfig方式
Configuration 注解是JavaConfig形式基于Spring IOC容器配置类使用的一种注解。在启动类里边标注@Configuration 也表示它是一个IOC容器的配置类。
  1. public class DemoClass {
  2.     public void say(){
  3.         System.out.println("sya hello ... ");
  4.     }
  5. }
复制代码
  1. @Configuration
  2. @Import(UserClass.class)
  3. public class DemoConfiguration {
  4.     @Bean
  5.     public DemoClass getDemoClass(){
  6.         return new DemoClass();
  7.     }
  8. }
复制代码
  1. public class DemoConfigurationMain {
  2.     public static void main(String[] args) {
  3.         ApplicationContext ac = new AnnotationConfigApplicationContext(DemoConfiguration.class);
  4.         DemoClass bean = ac.getBean(DemoClass.class);
  5.         bean.say();
  6.     }
  7. }
复制代码
3.2 Configuration本质

Configuration注解本质就是一个Component注解,会被AnnotationConfigApplicationContext 加载,而AnnotationConfigApplicationContext 是ApplicationContext 的具体实现,会根据配置注解启动应用上下文。所以在Main中通过AnnotationConfigApplicationContext 加载JavaConfig后,可以得到IOC容器中Bean的实例。
  1. @Configuration  //也会被Spring容器托管,注册到容器中,因为本身就是一个@Component
  2. @ComponentScan("com.kuang.pojo")
  3. @Import(MyConfig2.class)
  4. public class MyConfig {
  5.     //注册一个Bean相当于之前写的一个Bean标签
  6.     //这个方法的名字就相当于Bean标签中的id属性
  7.     //这个方法的返回值,就相当于Bean标签中的class属性
  8.     @Bean
  9.     public User getUser(){
  10.         return new User();  //返回要注入到Bean的对象
  11.     }
  12. }
复制代码
  1. public class MyTest {
  2.     public static void main(String[] args) {
  3.         //如果完全使用了配置类方式去做,只能通过AnnotationConfigApplicationContext来获取容器,通过配置类的class对象加载
  4.         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
  5.         User getUser = (User) context.getBean("getUser");
  6.         System.out.println(getUser.getName());
  7.     }
  8. }
复制代码
  1. @Component
  2. public class User {
  3.     private String name;
  4.     public String getName() {
  5.         return name;
  6.     }
  7.     @Value("xxx")
  8.     public void setName(String name) {
  9.         this.name = name;
  10.     }
  11.     @Override
  12.     public String toString() {
  13.         return "User{" +
  14.                 "name='" + name + '\'' +
  15.                 '}';
  16.     }
  17. }
复制代码
3.3 ComponentScan注解

相当于xml配置文件中的context:component-scan ,主要作用是扫描指定路径下标识了需要装配的类,自动装配到IOC容器中
  1. @Configuration  //也会被Spring容器托管,注册到容器中,因为本身就是一个@Component
  2. @ComponentScan("com.kuang.pojo")
  3. @Import(MyConfig2.class)
  4. public class MyConfig {
  5.     //注册一个Bean相当于之前写的一个Bean标签
  6.     //这个方法的名字就相当于Bean标签中的id属性
  7.     //这个方法的返回值,就相当于Bean标签中的class属性
  8.     @Bean
  9.     public User getUser(){
  10.         return new User();  //返回要注入到Bean的对象
  11.     }
  12. }
复制代码
3.4 Import注解

等同于xml形式下的 注解,将多个分开的容器合并在一个容器中。
方式一:@Import,直接@Import(MyConfig2.class)
方式二:ImportSelector,动态加载实现ImportSelector接口
方式三:ImportBeanDefinitionRegistrar方式,实现ImportBeanDefinitionRegistrar 接口
3.5 深入EnableAutoConfiguration原理

EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class) 导入第三方的提供的Bean配置类AutoConfigurationImportSelector
  1. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  2.     if (!this.isEnabled(annotationMetadata)) {
  3.         return NO_IMPORTS;
  4.     } else {
  5.         try {
  6. // 加载META-INF/spring-autoconfigure-metadata.properties 下的元数据信息
  7.             AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
  8.             AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
  9. // 获取候选加载的配置信息 META-INF/spring.factories
  10.             List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
  11. // 去掉重复的配置信息
  12.             configurations = this.removeDuplicates(configurations);
  13. // 排序
  14.             configurations = this.sort(configurations, autoConfigurationMetadata);
  15.             // 获取 注解中配置的 exclusion 信息
  16. Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
  17. // 检查
  18.             this.checkExcludedClasses(configurations, exclusions);
  19. // 移除需要排除的信息
  20.             configurations.removeAll(exclusions);
  21. // 过滤,检查候选配置类上的注解@ConditionalOnClass,如果要求的类不存在,则这个候选类会被过滤不被加载
  22.             configurations = this.filter(configurations, autoConfigurationMetadata);
  23. // 广播事件
  24.             this.fireAutoConfigurationImportEvents(configurations, exclusions);
  25.             // 返回要被加载的类数组
  26. return (String[])configurations.toArray(new String[configurations.size()]);
  27.         } catch (IOException var6) {
  28.             throw new IllegalStateException(var6);
  29.         }
  30.     }
  31. }
复制代码
EnableAutoConfiguration 会帮助SpringBoot应用将所有符合@Configuration 配置都加载到当前SpringBoot创建的IOC容器,这里面借助了Spring框架提供的一个工具类SpringFactoriesLoader的支持。以及用到了Spring提供的条件注解@Conditional,选择性的针对需要加载的bean进行条件过滤。
3.6 关于条件过滤

分析AutoConfigurationImportSelector的源码时,会先扫描spring-autoconfiguration-metadata.properties文件,最后在扫描spring.factories对应的类时,会结合前面的元数据进行过滤,为什么要过滤呢? 原因是很多的@Configuration其实是依托于其他的框架来加载的,如果当前的classpath环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以有效的减少@configuration类的数量从而降低SpringBoot的启动时间。
4 总结

SpringBoot自动装配实现是从classpath中搜寻spring.factory自动装配的核心文件,将包下对应的org.springframework.boot.autoconfigure的配置项通过反射实例化为对应标注的@Configuration的JavaConfig形式的IOC容器配置类,将然后汇总为实例加载至IOC容器中。
备注:思路还是不太清晰,后续还需再整理一遍深入理解。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦见你的名字

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表