ToB企服应用市场:ToB评测及商务社交产业平台

标题: 0.o?让我看看怎么个事儿之SpringBoot自动配置 [打印本页]

作者: 科技颠覆者    时间: 2024-4-7 16:32
标题: 0.o?让我看看怎么个事儿之SpringBoot自动配置
学习 SpringBoot 自动配置之前我们需要一些前置知识点:
Java注解,看完就会用
学会@ConfigurationProperties月薪过三千
不是银趴~是@Import!
@Conditional+@Configuration有没有搞头?
首先我们提出2个问题:
SpringBoot 是干什么的?
是用来简化 Spring 原生的复杂的 xml 配置的进阶框架。
自动配置是什么?
我们用另外一个问题回答这个问题。
我们在 SpringBoot 开发中,就写了几个配置,怎么连接上的数据库?
  1. spring:
  2.   datasource:
  3.     driverClassName: com.mysql.cj.jdbc.Driver
  4.     url: jdbc:mysql://192.0.0.1:3306/test?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
  5.     username: root
  6.     password: root
复制代码
在新手村时期,我们照着教程生搬硬抄的时候可能也想过这个问题,今天就来简单探究一下。
再次强调:
看明白本篇内容需要前置知识点,尤其是 @Import 注解。
这一切都要从 @SpringBootApplication 注解讲起。
@SpringBootApplication

@SpringBootApplication 注解是一个复合注解,它由如下三个注解组成。
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration  // 第一个
  6. @EnableAutoConfiguration  // 第二个
  7. @ComponentScan(excludeFilters = {  // 第三个
  8.         @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  9.         @Filter(type = FilterType.CUSTOM,
  10.                 classes = AutoConfigurationExcludeFilter.class) })
  11. public @interface SpringBootApplication {
  12. }
复制代码
  1. @SpringBootApplication
  2. ├── @ComponentScan
  3. ├── @SpringBootConfiguration
  4. │   └── @Configuration
  5. └── @EnableAutoConfiguration
  6.     ├── @Import(AutoConfigurationImportSelector.class)
  7.     └── @AutoConfigurationPackage
  8.         └── @Import(AutoConfigurationPackages.Registrar.class)
复制代码
@SpringBootConfiguration
@ComponentScan
@EnableAutoConfiguration
从注解的中文意思中也可以看出来,第三个 @EnableAutoConfiguration 是与我们自动配置紧密相关的。
我们先快速搞定前2个。
@SpringBootConfiguration

这个最简单,把头套摘下来,他就是一个普普通通的 @Configuration 注解包装而成而已,表示当前类是一个配置类。
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Configuration // 本体在这
  5. public @interface SpringBootConfiguration {
  6. }
复制代码
@ComponentScan

可以指定basePackageClasses或basePackages(或其别名value)来定义要扫描的特定包。如果没有定义特定包,扫描将从声明此注解的类的包开始。
顾名思义就是扫描Component。
扫描哪里?
可以通过该注解的属性指定Spring应该扫描的包。如果没有指定包,则默认扫描声明 @ComponentScan 的类所在的包及其子包。
哪些Component?
使用 @Component, @Service, @Repository, @Controller 等注解的类。
扫描了做什么用?
将扫描到的组件注册为Spring的Bean,加入到ioC容器进行统一管理。
@EnableAutoConfiguration

这是自动配置的核心注解!
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. }    
复制代码
我们能看到,其中有2个注解:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage

我们再点进去看一下,发现它又是一个 @Import 。
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @Import(AutoConfigurationPackages.Registrar.class)
  6. public @interface AutoConfigurationPackage {
  7. }
复制代码
@Import(AutoConfigurationPackages.Registrar.class) 中的 Regisgrar 类如下:
  1. static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
  2.     @Override
  3.     public void registerBeanDefinitions(AnnotationMetadata metadata,
  4.                                         BeanDefinitionRegistry registry) {
  5.         register(registry, new PackageImport(metadata).getPackageName());
  6.     }
  7.     @Override
  8.     public Set<Object> determineImports(AnnotationMetadata metadata) {
  9.         return Collections.singleton(new PackageImport(metadata));
  10.     }
  11. }
复制代码
如果你有去好好看 @Import 注解的那篇文章,就会知道这是 ImportBeanDefinitionRegistrar 接口实现的方式。
这种方式提供一种手动方式灵活注册 bean。
在这里,我们根据两个提示就可以知道其功能:
• @AutoConfigurationPackage 是自动配置包的意思
• register(registry, new PackageImport(metadata).getPackageName()); 根据包名注册 bean
总结一下就是:
根据通过注解提供的元数据,动态地向 Spring 容器中注册特定包中的类作为 beans。
@Import(AutoConfigurationImportSelector.class)

如果你有去好好看 @Import 注解的那篇文章,就会知道这是 ImportSelector接口实现的方式。
这种方式只需实现 selectImports 方法,并以数组的形式返回要导入的类名,即可实现批量注册组件。
AutoConfigurationImportSelector 类中通过自己的源码实现了如下一个功能:
把 spring-boot-autoconfigure 依赖中 META-INF/spring.factories 文件中需要自动配置的类名读取到数组中。
它长这个样子:
  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  3. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  4. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  5. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  6. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
  9. ...
复制代码
那它到底怎么读取的?
这里我们不讨论具体实现,有兴趣有实力的可以扒源码自己看一下。
当然这些类不会全部都用到,经过筛选,去除重复、去除相应功能模块未开启的配置类、去除人为exclude掉的,将剩余的最终配置类全类名String数组返回。
最后我们再来回收一下开始的那个问题。
我们在 SpringBoot 开发中,就写了几个配置,怎么连接上的数据库?
我们简单捋一下:
SpringBoot 启动。
@SpringBootApplication 注解生效。
@EnableAutoConfiguration 注解生效。
@Import(AutoConfigurationImportSelector.class) 注解生效。
读取到了org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration。
注册一个数据源bean。
读取到 xml 的数据源配置。
大功告成!
往期推荐:
● 终于搞懂动态代理了!
● 学会@ConfigurationProperties月薪过三千
● 学一点关于JVM类加载的知识
● Java注解,看完就会用
● Java反射,看完就会用
● @Value是个什么东西

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




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4