概述
前言
SpringBoot之所以可以做到简化配置文件直接启动,无外乎是其内部的两种设计策略:开箱即用和约定大于配置。
开箱即用:在开发过程中,通过maven项目的pom文件中添加相关依赖包,然后通过相应的注解来代替繁琐的XML配置以管理对象的生命周期。
约定大于配置:由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。
一、自己定义一个@EnableConfiguration和ImportSelector,实现自动装配
需要一下几个步骤(此实践基于xx课程):
- 定义RedisConfiguration类,用@Configuration标注方法,并在用@Bean标注的方法,返回bean实例
- 自定义@EnableConfiguration注解
- 自定义GpDefineImportSelector类,实现ImportSelector接口,并重写selectImports方法,selectImports方法里返回我们需要自动装配的RedisConfiguration等类的全路径字符串数组
- 将自定义的@EnableConfiguration注解,放到启动类上
具体代码如下:
1.1 RedisConfiguration.class
@Configuration
public class RedisConfiguration {
@Bean
public GpRedisTemplate gpRedisTemplate(){
return new GpRedisTemplate();
}
}
1.2 自定义@EnableConfiguration注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(GpDefineImportSelector.class)
public @interface EnableConfiguration {
}
1.3 自定义GpDefineImportSelector类
public class GpDefineImportSelector implements ImportSelector{
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//动态导入bean, 告诉了Spring , 两个配置类在哪里
//TODO 在这里去加载所有的配置类就行?
// 通过某种机制去完成指定路径的配置类的扫描就行?
//package.class.classname
return new String[]{GpSqlSessionFactory.class.getName(), RedisConfiguration.class.getName()};
}
}
1.4 将自定义的@EnableConfiguration注解,放到启动类上
这样GpRedisTemplate.class的对象就可以自动装配到spring容器中了。
二、自动装配原理
2.1 @SpringBootApplication注解
先看看Springboot主配置类上的@SpringBootApplication注解:
如上图, @SpringBootApplication其实是包含了三个主要的注解:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
2.1.1 @SpringBootConfiguration
首先看@SpringBootConfiguration注解:
这个注解很简单,表名该类是一个Spring的配置类。
2.1.2 @EnableAutoConfiguration
该注解包含两个重要的注解:
- @AutoConfigurationPackage
- @Import(EnableAutoConfigurationImportSelector.class)
2.1.2.1 @AutoConfigurationPackage
这个注解是自动配置包,主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class。
来看下这个Registrar:
我们打个断点看一下:
它的包路径是什么呢?——就是我们主配置类同级目录的包:
那么metadata是什么呢:
它就是我们的主配置类——MyProjectMyProjectApplication类:
由上面我们可以推测:就是将主配置类(即@SpringBootApplication标注的类)所在包及子包里面所有组件扫描加载到Spring容器。
现在包扫描路径获取到了,那具体加载哪些组件呢,看看下面这个注解。
2.1.2.2 @Import(EnableAutoConfigurationImportSelector.class)
@Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:EnableAutoConfigurationImportSelector.class。
它有一个实现其他类的selectImports方法,这个方法的本质是:将所有需要导入的组件以全类名的方式返回;
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。
那他是如何获取到这些配置类的呢,看看上面这个方法:
它会给容器导入很多的配置类(通常由第三方实现,类名是xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件:
通过debug,我们继续探究:
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取key为EnableAutoConfiguration(实际上是EnableAutoConfiguration的全路径明)指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。
以druid-spring-boot-starter为例,我们看一下spring.factories:
由上我们可以得出结论:
当我们的SpringBoot项目启动的时候,会先导入AutoConfigurationImportSelector,这个类会帮我们选择所有候选的配置,我们需要导入的配置都是SpringBoot帮我们写好的一个一个的配置类,那么这些配置类的位置,存在与META-INF/spring.factories文件中,通过这个文件,Spring可以找到这些配置类的位置,于是去加载其中的配置。
拓展:spring.factories中存在那么多的配置,每次启动时都是把它们全量加载吗?这显然是不现实的。
这其实也是我在看源码的时候存在疑问的地方,因为其中有一个注解并不常用,我们点开一个配置类就可以看到。
@ConditionalOnXXX:如果其中的条件都满足,该类才会生效。
所以在加载自动配置类的时候,并不是将spring.factories的配置全量加载进来,而是通过这个注解的判断,如果注解中的类都存在,才会进行加载。
2.3 @ComponentScan
ComponentScan这个注解是大家接触得最多的了,相当于xml配置文件中的<context:component-scan>。 它的主要作用就是扫描指定路径下的标识了需要装配的类,自动装配到spring的Ioc容器中。
标识需要装配的类的形式主要是:@Component、@Repository、@Service、@Controller这类的注解标识的类。
所以上图需要加一块@ConditionOnClass判断:
三、SPI
之前有文章讲过SPI,可以看看:dubbo内核简介(附部分源码解读)
四、自己构建一个starter组件
之前也有文章逐步讲解并实践过:年轻人的第一个自定义Springboot starter
在上面我写的starter时,我没有用到下面两个注解,但在很多时候,可能会用到下面两个注解:
- @ConditionalOnClass(xx.class)
- @EnableConfigurationProperties(xxProperties.class)-上面的例子用到了
4.1 @ConditionalOnClass
4.2 @EnableConfigurationProperties
作用:@ConfigurationProperties 注解的类生效。
如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。
关于这个注解,具体可以查看上面的链接例子。
最后
以上就是难过雪碧为你收集整理的SpringBoot自动装配原理与自己写一个starter前言一、自己定义一个@EnableConfiguration和ImportSelector,实现自动装配二、自动装配原理三、SPI四、自己构建一个starter组件的全部内容,希望文章能够帮你解决SpringBoot自动装配原理与自己写一个starter前言一、自己定义一个@EnableConfiguration和ImportSelector,实现自动装配二、自动装配原理三、SPI四、自己构建一个starter组件所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复