SpringBoot的SPI机制源码解析
什么是SPI?
SPI全称为Service Provider Interface(Service Provider Interface),是JDK内置的一种面向接口编程的机制。SPI的作用就是为这些接口寻找实现类。具体来说,当服务接口的实现类存在于classpath路径下的第三方jar包中,可以通过SPI机制自动发现并加载实现类,而无需在代码中显示的指定对象的创建。
SpringBoot中的SPI
SpringBoot中的SPI是基于JDK的SPI机制进行二次开发后的一种轻量级的SPI实现。在SpringBoot中,我们可以通过扩展SPI接口的方式轻松地实现插件扩展,在实现上还提供了比JDK SPI更灵活、易用和便捷的方式。
在SpringBoot中,插件的实现有两种方式:
- 实现指定的接口
- 使用@Service注解
SPI原理
1.在SPI机制中,服务接口部分称作Service,而具体实现服务的类称为Service Provider。
2.可以使用Java提供的SPI进行动态扩展,所以在使用SPI服务的过程中,需要编写一个服务接口,在服务提供者中编写该接口的实现类,并在服务配置文件中配置实现类的全路径地址。
3.在代码中可以使用ServiceLoader进行服务加载。
SpringBoot中的SPI注解扫描
SpringBoot在版本2.1后为我们提供了一个很方便的工具类用于自动侦测classpath下所有的SPI实现类,即SPI自动配置机制。
SpringBoot通过@EnableAutoConfiguration注解自动侦测classpath下所有的auto-configuration包以及META-INF/spring.factories文件。spring.factories文件内部存放当前应用需要启动的配置类列表。而配置类中可以使用@Conditional注解来控制当前应用装载此配置类。
SpringBoot处理SPI的过程
SpringBoot将SPI进行了二次封装,对Spring的ApplicationContext进行包装。其流程如下:
- SpringBoot创建BeanFactory实例,并注册相关的BeanDefinition
- SpringBoot创建ApplicationContext并使用BeanFactory作为其内部beanFactory
- SpringBoot启动ApplicationContext
- 扫描SPI注解
- 注册注解标注的SPI服务
- 启动初始化
两个示例
示例一:实现指定的接口
1.创建一个SPI接口:
public interface DemoService {
String sayHello(String name);
}
2.编写DemoServiceImpl实现DemoService:
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
3.在classpath下创建/META-INF/services/com.example.demo.DemoService,编写实现类的全路径名称:
com.example.demo.impl.DemoServiceImpl
4.在代码中使用ServiceLoader进行服务加载:
ServiceLoader<DemoService> serviceLoader = ServiceLoader.load(DemoService.class);
for (DemoService demoService : serviceLoader) {
System.out.println(demoService.sayHello("world"));
}
输出结果为:Hello, world!
示例二:使用@Service注解
1.编写API接口:
public interface ApiService {
String sayHello(String name);
}
2.编写实现类:
@Service
public class ApiServiceImpl implements ApiService{
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
3.在启动类中使用@ComponentScan注解,指定扫描com.example.demo包:
@SpringBootApplication
@ComponentScan("com.example.demo")
public class SpiApplication {
public static void main(String[] args) {
SpringApplication.run(SpiApplication.class, args);
}
}
4.使用@Autowired注解进行注入
@RestController
@RequestMapping("/api")
public class ApiController {
@Autowired
private ApiService apiService;
@GetMapping("/hello/{name}")
public String sayHello(@PathVariable String name){
return apiService.sayHello(name);
}
}
5.访问:http://localhost:8080/api/hello/world
输出结果为:Hello, world!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot的SPI机制源码解析 - Python技术站