springboot和微服务的关系是什么?
回答:所有的微服务组件,都是集成到springboot上面,spring cloud也是一样,在使用springcloud的时候,它应该和springboot在版本上兼容。
1、第一特性,EnableAutoConfiguration ,译为自动装配。
2、第二特性,Starter启动依赖,依赖于自动装配的请求。
3、第三特性,Actuator监控,提供一些endpoint,这些endpoint可以基于http jmx 等形式去进行访问health信息,metrics信息。
4、第四特性,Spring Boot CLI,它是为springcloud提供的springboot命令行操作的功能,它通过groovy脚本快速构建springboot的应用,用得很少,一般还是基于idea应用构建springboot应用,略过。
小结:自动装配和启动依赖是不同的,两者关系是启动依赖依赖于自动装配,监控提供一些访问形式。
问题:能够实现@Autowired依赖注入的前提是是IOC中存在这个bean的实例,那么是谁装载了这个bean实例?
回答:spring中装载bean实例包括三种方式:xml文件 configuration类 enable注解,现在这三种方式我们都没做,但是为什么springboot可以实现bean装配,这就是springboot的自动装配,完成bean的自动装载,只要写出来@Autowired,自动装配的原理是怎么实现的。
springboot为什么能够完成自动装配?
一句话总结,在pom.xml中引入的依赖(即jar包),都被约定好带有统一的格式,都有XxxConfiguration类,使用时springboot直接对其扫描,就完成了装配,但是这是对开发程序员不可见的,所以被称为自动装配。每个第三方的starter里面都有一个配置类XxxConfiguration类,这是一种约定。
Springboot自动装载问题1:Spring引擎怎么知道第三方组件starter里面具体配置类在哪里?
Springboot自动装载问题2:如何实现批量扫描配置类XxxConfiguration redis mybatis dubble?
spring静态装配三种方式:xml文件 Configuration配置类 @Enable模块装配
spring动态装配两种方式:ImportSelector接口 Registator接口
每一个第三方starter里面都有一个配置类XxxConfiguration,Springboot中使用多个第三方组件,如何批量扫描多个配置类XxxConfiguration
答案:批量bean加载机制。spring存在两种动态bean装载机制,一种是ImportSelector接口,一种是Registator接口,都是接口,本文介绍ImportSelector接口。
动态装载:根据运行时上下文的具体运行条件来状态来装载配置类XxxConfiguration,不同于@Conditional。
这部分给出一个项目,模拟springboot自动装配,项目结构如下:
给出一个mybatis bean类、mybatis 模拟配置类、redis bean类、redis 模拟配置类
模拟ImportSelector实现类,实现ImportSelector接口,返回配置类
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 在这里去加载所有的配置类
// 通过某种机制去完成指定路径的配置类的扫描就行?
// spring只需要知道 package.class.classname 就行了。
return new String[]{MybatisConfiguration.class.getName(), RedisConfiguration.class.getName()};
}
}
如何让SpringbootApplication知道MyImportSelector返回的配置类?只需要声明一个注解就可以完成。
定义一个注解,@Import(ImportSelector接口实现类.class)
SpringApplicationdemoApplication类中使用这个注解
本项目中,其实SpringbootApplication不要使用@MyEnableConfiguration也可以,因为SpringbootdemopageApplication所在包为package com.example.demo;但是,两个bean所在包为package com.example.demo.mybatis 和 package com.example.demo.redis,这样,启动SpringbootdemopageApplication,会扫描所在包及其子包,就扫描到了两个bean。
如果SpringbootdemopageApplication在com.example.demo.springbootdemo,必须配置@MyEnableConfiguration注解,启动的时候,扫描@MyEnableConfiguration注解,然后知道它@Import(MyImportSelector.class),在MyImportSelector.class中,spring才知道两个配置类的路径,才有了下面的装载bean并打印出来。
貌似MyImportSelector 返回值中直接放bean类会出现重复装配的情况,总之,最好放配置类。
小结:这个实例告诉我们,springboot底层使用ImportSelector接口+注解动态装载,无论第三方组件(项目中com.example.demo.mybatis 和 com.example.demo.redis模拟第三方组件,每一个组件都包括配置类和实体bean)的配置在哪里,都可以用ImportSelector接口找到,并用注解告诉springboot,解决了第一个问题。对于n个配置类(项目中mybatis和redis模拟两个配置类),可以批量配置,不是问题。
注意1:使用@ComponentScan或base-package不可以,它是静态装配,需要把扫描的路径写死,但是在使用一个第三方组件的时候,你是不知道它的bean或配置类在哪里的,这就是静态装配的局限,只能用动态装配。
注意2:使用@Contional 也不仅,仅仅只是一个给出一个判断,装配还是不装配,当然下文我们的有条件配置。
**可以看到,springboot的动态装载的底层实现的@SpringBootApplication注解和我们的模拟的时候的自定义注解@MyEnableConfiguration底层是一样的,都是集成ImportSelector接口实现其selectImports返回配置类数组。**难怪刚刚开始的redisTemplate可以自动装配。
@Autowird
private RedisTemplate redisTemplate; // 自动装载
第一,AutoConfigurationImportSelector 自动配置ImportSelector :getAutoConfigurationEntry 获得自动配置/自动装载实体
第二,SpringFactoriesLoader 表示 :spring.factories 加载
开发程序员使用的时候,只要直接使用
@Autowired
private RedisTemplate<string,string> redisTemplate; // 自动配置好了的,直接用就好
问题:刚才的项目只是在自己的项目中模拟,那么具体实践中,spring引擎怎么知道具体starter配置类在哪里?
回答:第一,所有starter遵循统一的约定,所有的starter组件,都需要一个META-INF/spring.factories文件,如下:
第二,springboot直接扫描配置文件(org.redis.RedisConfiguration org.mybatis.MybatisConfiguration)就好了,如下图:
SPI 全称 Service provider interface ,服务提供接口,这里以各个不同的数据库驱动为例,如图:
SPI 就是我们提供接口,接口的具体实现由第三方来做(这里,不同的数据库驱动是不同的,由数据库厂商来完成),Java程序只要导入不同的jar包就可以执行,这就是SPI的扩展,就是服务提供接口的扩展。
为什么说spring.factories也是SPI,spring.factories 是基于key-value键值对的,其中key就是同一个Configuration,value由第三方具体实现;因为每一个starter组件的jar包都有一个Configuration注解,提供一个与springboot沟通接口,其内部具体实现由第三方来做(redis mybatis dubbo),springboot只要导入不同的jar包(redis依赖 mybatis依赖 dubbo依赖)就好。
一句话总结DPI:
DPI 本身包含默认实现,但是也提供扩展点,需要的话可以替换,提高伸缩性和灵活性。
DPI设计得以实现需要满足以下条件:
1、需要在classpath目录下创建一个META-INF/services
2、在该目录下创建一个扩展点的全路径名
2.1 文件中填充这个扩展点的实现
2.2 文件编码格式UTF-8
3、ServiceLoader去进行加载
注意事项:META-INF和services目录必须分开创建
maven quickstart 项目,maven clean maven install 之后变成jar包;
maven webapp 项目,maven clean maven install 之后变为war包。
starter组件与自动装配紧密相连,因为所有的第三方的starter组件都是遵循自动装配的约定,提供spring.factories文件,提供配置类给springboot扫描完成自动装配。
对于官方的springboot starter,不存在spring.factories,那么为什么不存在spring.factories,它又是如何加载的?
原来,starter包包括两种,
官方包 spring-boot-starter-xxx 不存在 spring.factories 如spring-boot-starter-data-redis spring-boot-starter-thymeleaf
第三方包 xxx-spring-boot-starter 一定存在spring.factories
以Redis为例,其配置类RedisAutoConfiguration不存在 spring-boot-starter-data-redis 里面 ,而是不存在spring-boot-autoconfigure包,
既然如何,springboot又是如何找到配置类RedisAutoConfiguration的呢?
答案是条件注解。
小结,官方包的依赖就是条件触发。
这里面这些都只需要导入依赖就好,只有第三方包才需要自己写spring.factories。
新建maven quickstart项目:autoconfiguredemo
maven clean maven install 成为一个jar包,给springboot工程去使用
新建一个maven quickstart 工程 springbootcore2,导入依赖
现在在第一个工程Configuration配置类上面使用条件注解,表示要满足某一个条件才装载,就使用 @ConditionalOnClass({RedisOperations.class}) 就好了。
先导入依赖
在springboot中存在一个spring-autoconfigure-metadata.properties文件,它也是一种配置文件。
这种配置文件只是,使用者需要按要求这样配置,实际上我们自己的工程也可以实现这种配置文件并打成jar包的。
源工程
并不是所有的条件配置都是写在类上面的注解上面的,也可以通过spring-autoconfigure-metadata.properties配置文件去写,且看mybatis
这里是mybatis的条件配置文件 spring-autoconfigure-metadata.properties
本文介绍Springboot自动装配的特性,从使用redis引入了自动装配,然后理解自动装配、模拟实现、阅读springboot源码,最后引入条件触发和demo实现。
天天打码,天天进步!!!
自动装配模拟工程代码:https://download.csdn.net/download/qq_36963950/12555256
SPI设计思想工程代码:https://download.csdn.net/download/qq_36963950/12555258
自动装配+条件注解+条件配置文件工程代码:https://download.csdn.net/download/qq_36963950/12555260