1. Spring Auto Import(基于 @EnableAutoConfiguration)
@SpringBootApplication
注解中有一个@EnableAutoConfiguration
注解,它负责启用了springboot
的自动装配,实现自动装配前会准备一个预定义的清单文件(AutoConfiguration.imports/spring.factories)
然后根据类路径生成候选自动配置类,在经过条件判断,最后这些配置类会被实例化并注册到ioc容器中
AutoConfiguration.imports 文件的生成
SpringBoot3中提供了@AutoConfiguration注解,在借助构建工具(如maven)及
spring提供的spring-boot-maven-plugin
进行构建时,会识别@AutoConfiguration注解将这些带有注解的类全限定名路径存储在AutoConfiguration.imports 文件,这些类全部成为候选自动配置类。
读取及筛选配置类的流程
这个方法就是最后将列表中所有的配置类注册到ioc容器上,
这里的条件判断指的是配置类上的@Conditional 系列注解,方法最后,调用 getConfigurations() 方法获取候选配置类的列表,并将其转换为字符串数组返回。
实现装配
最后装配是通过EnableAutoConfiguration.class
上的@Import(AutoConfigurationImportSelector.class)
实现的。
Import
注解通过Spring 的 ImportSelector 和 ImportBeanDefinitionRegistrar 接口提供了两种方式来实现更复杂的导入逻辑。
2.@Import配合条件注解
@Import注解最后指向返回的都是配置类或是配置类的全限定名,所以说重构selectImports方法或者是配置类上的@Conditional 系列注解,它都是在装配到ioc容器前的筛选的一步,通过@Configuration标识类将最后通过@Conditional 系列注解的@bean装配到ioc容器。
标注: 这里的config配置类是在ioc容器中的,所以通过@Conditional 系列注解进行装配是动态的。所以我说
都是在装配到ioc容器前的筛选的这个说法并不准确。
通过@Import配合条件注解可以指向你的自定义配置类,在你的配置类可以加上@Conditional 系列注解使其在什么情况下装配你的bean。
最后像这样,你完成了基于你逻辑的自定义自动装配。
3.SPI
jdk的SPI机制
Message 接口:提供服务的接口
public interface Message {
String getMessage();
}
HelloMessageService ,HiMessageService 实现服务的实现类
public class HelloMessageService implements Message{
@Override
public String getMessage() {
return "Hello Message Service!";
}
}
public class HiMessageService implements Message{
@Override
public String getMessage() {
return "Hi,Message Service";
}
}
Java的类加载器从META-INF/services/
目录下加载Message
服务文件,文件名命名规则全限定类名例如:
# 文件位置:src/main/resources/META-INF/services/com.example.service.PaymentService
com.example.service.impl.HelloMessageService # 此处是文件内容
com.example.service.impl.HiMessageService
package cn.Jason;
import cn.Jason.JdkSPI.Message;
import java.util.ServiceLoader;
public class MyApp {
public static void main(String[] args) {
ServiceLoader<Message> loader = ServiceLoader.load(Message.class);
for (Message message : loader) {
System.out.println(message.getMessage());
}
}
}
#执行结果
Hello Message Service!
Hi,Message Service
这里注意一点,loader
迭代到某类时那个实现类才实例化。
SpringSPI
因为spring 的实例化在容器内进行,所以这里只需完成服务发现和对应的实现配置类,将他们注册到容器就完成了自动装配功能。
在springboot2.7
以下版本META-INF/spring.factories
的文件中这样的键值对
cn.Jason.JdkSPI.Message =\
com.example.impl.HelloMessageService ,\
com.example.impl.HiMessageService
对比jdk的服务文件,spring
将服务的全限定类名作为键,将实现配置类作为值。多个配置用,
分隔。
Springboot2与SpringBoot3处理区别
springboot2
在springboot2.7
以下版本spring.factories
文件中以EnableAutoConfiguration
为键,它会映射到一组自动配置类的列表(全限定类名)。
springboot2.7
以下版本读取到文件之后的逻辑就是通过SpringFactoriesLoader
根据@EnableAutoConfiguration
的全限定类名作为键,查找其对应的实现类列表。
springboot3
AutoConfiguration.imports
文件的内容则不是键值对格式,此文件中的每一行都是一个自动配置类的全限定类名(没有键值对)。
由于不是键值对格式,所以直接将autoconfigure-imports
文件中的类名汇总成一个列表。
最后
这里也是对应了我最开始说的AutoConfiguration.imports 文件
的生成,将候选配置类列表进行筛选,再通过重构selectImports方法
将配置类都注册到ioc容器
中,然后进行通过@Conditional 系列注解
进行条件判断,实现动态装配bean
。