1 SpringBoot介绍
SpringBoot是在架构演进过程中,优化Spring开发流程而出现的,是对Spring开发进行了再次简化。
SpringBoot相比Spring做了哪些优化?
- 简化了Bean对象注入IoC容器的流程
- 对配置文件进行了统一管理
- 容器内置化
main -> run -> refreshContext -> invokeBeanFactoryPostProcessor -> 扫描带有@Import注解的类 -> 调用selectImports方法
2 SpringBoot自动装配
2.1 SpringBoot集成Redis Demo
比如SpringBoot集成redis,只需要以下三步就可以通过RedisTemplate使用redis,不需要自己将RedisTemplate注入到IoC容器,这就是自动装配
(1) 导包
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
(2) redis相关配置
# master的名字是sentinel.conf配置文件里面的名称
# sentinel monitor redis-master 192.168.8.203 6379 2
spring.redis.sentinel.master=redis-master
spring.redis.sentinel.nodes=192.168.8.203:26379,192.168.8.204:26379,192.168.8.205:26379
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1s
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
(3) 通过@Autowired注入RedisTemplate
2.2 自动装配过程
SpringBoot项目启动 –> 扫描@SpringBootApplication –> 里面带了@Configuration注解,表示该注解修饰的类是配置类 –> @EnableAutoConfiguuration注解里有@Import注解 –> @Import注解实际上导入了所有需要自动装配的配置类 –> @Import注解里有AutoConfigurationImportSelector类 –> AutoConfigurationImportSelector间接实现了ImportSelector接口
@EnableAutoConfiguuration
@Import(AutoConfigurationImportSelector.class) -> 会导入所有需要自动装配的配置类
AutoConfigurationImportSelector.class -> 返回配置类的类名
如何找到所有配置类? 通过SPI机制找到需要自动装配的配置类
RedisAutoConfiguration类就是自动注入RedisTemplate的配置类
3 SPI(Service Provider Interface)
甲方调用乙方接口,甲方制定好接口,然后自己调用自己制定的接口,由乙方实现接口;
(1) 甲方提供接口
(2) 乙方依赖甲方接口所在的包,并且创建接口实现类
(3) 在乙方实现类所在jar包中告诉甲方,实现类在哪,具体是什么实现类
(4) 甲方依赖乙方的jar包之后再进行调用,最终调用乙方实现类方法
JDK SPI通过ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
Spring SPI通过SpringFactoriesLoader.loadSpringFactories
Dubbo SPI通过ExtensionLoader.load
3.1 Jdk SPI
在resources/META-INF/services下创建以配置类全路径为名的文件,文件内部列举其所有实现类,多个实现类换行分开
(1) 根据Prefix + 接口全路径找到文件
(2) 解析文件,获取文件中配置的实现类
(3) 循环遍历反射获取配置类并实例化
3.2 Spring SPI
在每个组件项目路径resources/META-INF/spring.factories中配置了配置类,通过key-value方式配置接口与实现类
3.3 Dubbo SPI
以负载均衡算法为例,在resources/META-INF/dubbo或者在classpath/META-INF/services路径下创建org.apache.dubbo.rpc.cluster.LoadBalance文件,文件内部列举自定义实现类
// key-value形式, key是别名, value是自定义负载均衡算法类全路径
myloadbalance=com.example.dubbo.loadbalance.MyLoadBalance
random=com.example.dubbo.loadbalance.RandomLoadBalance
public class MyLoadBalance implements LoadBalance {
@override
public void select() {
// TODO 负载均衡算法实现
}
}
@Controller
public class UserController {
// 使用自定义负载均衡算法
@DubboReference(loadBalance="myloadbalance")
IUserService userService;
}
(1) 加载文件,获取文件中配置的实现类
(2) 将所有实现类类名放到四个容器里面,不实例化
(3) 类调用的时候再实例化
4 SpringBoot启动源码分析
(1) 从main方法启动
(2) 判断当前项目运行环境类型,其实就是去所依赖的jar中寻找是否存在DispatcherHandler / DispatcherServlet
(3) 设置初始化器和监听器,用于对外扩展
(4) 创建环境变量environment,同时创建PropertySources容器,默认创建四个系统级别PropertySources
(5) 然后基于监听器机制,将本地配置文件,远程服务器的配置文件加入到PropertySources,进而加到Environment中
a. 确定文件所在目录,从5个路径下寻找(classpath/*, classpath/config/*, /*, /config/*, /config/*/*)
b. 确定文件名称(application.properties, application.yml)
c. 如果是本地配置文件则通过IO流去读,如果是远程配置文件则通过HTTP去读
d. 解析封装配置文件为PropertySource,并通过addLast追加到PropertySources
5 Starter组件
stater组件干了啥?
- 引springboot包
- 写RedisTemplate类
- 写配置类RedisAutoConfiguration,实现EnableAutoConfiguration接口
- 写spring.factories文件
- 打成jar包
xxx-spring-boot-starter与spring-boot-starter-xxx的区别?
- 前者是spring自身维护的starter,后者是第三方组件维护的starter
- spring自身维护的starter,目录下没有spring.factories文件,全都配置在spring-boot-autoconfigure项目中,但是不会全部注入到容器中,根据@ConditionalOnClass条件注入注解决定哪些配置类需要被注入到IoC容器中,而第三方组件维护的starter下都有spring.factories文件