SPI
spi : service provider interface : 是java的一种服务提供机制,spi 允许开发者在不修改代码的情况下,为某个接口提供实现类,来扩展应用程序
将实现类独立到配置文件中,通过配置文件控制导入:
public static void main(String[] args) {
ServiceLoader<Animal> load = ServiceLoader.load(Animal.class);
for (Animal animal : load) {
animal.sound();
}
}
就会导入Animal的两个实现类
问题:
- spi 和一般的面向接口变成有什么区别?,,使用spi导入和直接用,不是一样的吗
- 动态加载实现类
在一般的面向接口变成中,通常需要显示的创建实现类,,,通过spi机制,可以在运行时动态加载实现类,无需在代码中指定具体的实现类,代码更加灵活可扩展 - 配置文件
一般在面向接口编程中,通常在代码中显示的指定具体的实现类,,显示的注入实现类,,而spi使用配置文件META-INF/services
指定接口实现类,如果要新增或者切换实现类,那么只需要修改配置文件即可,,
- 动态加载实现类
spi使得应用程序设计,更具灵活性,模块化,可扩展性,,它通过动态加载实现类,解耦接口和实现,以及使用配置文件来实现这些特性,,从而使得应用程序更加智能的加载,和使用模块
springboot自动装配
springboot自动装配是 SPI 思想的一种应用
@SpringbootApplication
: 声明这个类是个引导类,或者叫 配置类
是一个复合注解
- @SpringbootConfiguration
- @ComponentScan : 扫描当前包下 及其子包的 @Component 标记的类
- @EnableAutoConfiguration
自动装配里面用了 @Import 和 ImportSelector接口,,
@Import和ImportSelector使用
创建了一个配置类 :
@Configuration
public class MyConfig {
@Bean
public Watermelon watermelon(){
return new Watermelon();
}
}
可以使用 @Import(MyConfig.class) 直接导入配置类,
//@ComponentScan
// @Import(MyConfig.class)
@Import(FruitConfigurationSelector.class)
public class FruitApplication {
public static void main(String[] args) {
// 默认启动web服务器,@ComponentScan会去扫web服务器
ConfigurableApplicationContext context = new SpringApplicationBuilder(FruitApplication.class)
.web(WebApplicationType.NONE) // 关闭web服务器
.run(args);
Watermelon watermelon = (Watermelon) context.getBean("watermelon");
System.out.println("watermelon = " + watermelon);
}
}
也可以使用 @Import 导入 ImportSelector 的实现类,,这个实现类返回一个数组,表示要注入的bean的全限定类名的集合
public class FruitConfigurationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{MyConfig.class.getName()};
}
}
@EnableXXXAutoConfiguration
写一个注解,在这个注解上面,使用@Import 导入若干要导入的Bean,,
为什么要有@EnableXXXAutoConfiguration : 模块装配
,如果同时需要几个模块,使用@EnableXXXAutoConfiguration 装配整合成一个
springboot中@EnableAutoConfiguration
ImportSelector 中的 selectImports方法
去导入bean,,
getCandidateConfigurations方法
去加载 spring.factories
中的配置,,预选配置再根据@Conditional去判断哪些要注入容器