SPI (Service Provider Interface)
Java SPI, META-INF/services/com.example.MyService:com.example.MyServiceImpl
Dobbo SPI,META-INF/dubbo/com.example.MyService:impl1=com.example.MyServiceImpl1
SpringSPI,META-INF/spring.factories:com.example.MyService=com.example.MyServiceImpl
问题背景和现象
最近同事由于新需求需要使用easy-poi包的其他功能,升级了版本,第二天的版本部分服务启动失败。日志如下:
Application run failed java.lang.IllegalStateException:
Annotation @EnableCircuitBreaker found, but there are no implementations. Did you forget to include a starter?
排查过程
之前没有遇到过类似问题,更不清楚@EnableCircuitBreaker是干什么,属于哪个包。网上的解决方案都是引入"spring-cloud-starter-netflix-hystrix"依赖即可。
不过问题就在于,我们环境里是有这个包spring-cloud-starter-netflix-hystrix-2.2.5.RELEASE.jar
的,这就尴尬了。我不禁对这些博主有些失望,进一步的在帖子中找到stack-over-flow的帖子
帖子主要意思:
- 这个问题的原因是应用在尝试加载一些spring集成的class文件时候没有找到导致的
- 你可以深入到报错的堆栈信息中找到带有"AutoConfiguration"字样的错误,以定位具体缺失的class
- 你还可以通过开启spring的debug日志去看到底在自动配置些什么东西?一旦定位到之后,可以通过
@EnableAutoConfiguration
注解进行排除
那么我又一步一步的去做。
开始尝试在堆栈中找AutoConfiguration,并没有。
开启debug之后,仍然没看到比较有价值的日志。
没有办法,只有去代码中找一下哪里在调用。幸好IDEA牛逼,可以直接查询jar包中的类名,直接定位到这个注解@EnableCircuitBreaker
,只找到一个地方有引用:
第一个就是注解本身,看下第二个:
看似有关系,但是又不知道关系在哪里。再次点击EnableCircuitBreaker注解查找引用的地方(注意,IDEA的2022.1.2社区版点不过去
):
到这里就有点快到出口的感觉了,这个spring.factories文件看着就很眼熟,这不就是SPI机制嘛。
EnableCircuitBreaker是属于spring-cloud-commons-2.1.0.RELEASE.jar
包;
HystrixCircuitBreakerConfiguration属于spring-cloud-netflix-hystrix-2.1.3.RELEASE.jar
包;
而HystrixCircuitBreakerConfiguration类根据Spring的SPI机制,作为EnableCircuitBreaker的具体实现,在启动的时候因为EnableCircuitBreaker被加载,这时候需要加载它的具体实现类,可以由于缺少spring-cloud-netflix-hystrix这个包,所以根本无从加载,所以报了Annotation @EnableCircuitBreaker found, but there are no implementations. Did you forget to include a starter?
这个错误,现在看来还是很贴心了。
那么,为什么会存在有spring-cloud-starter-netflix-hystrix包却没有spring-cloud-netflix-hystrix包的情况呢?starter不是包含了具体的包吗?后面找到原因是由于有同事删除了spring-cloud-netflix-hystrix的依赖,由于是使用的pom的多行注释,所以在使用find命令排查的时候误以为还在。
于是乎,将spring-cloud-netflix-hystrix包拷贝到环境中,good,不报这个注解的错误了,开始报其他错误了(因为spring-cloud-netflix-hystrix依赖hystrix-core-1.5.18.jar等包,依次拷贝过去就ok)。
至此,问题原因清楚了:SPI实现类缺失导致的问题。
总结
这里贴一个SPI的文章,JDK-SPI、Spring-SPI、Dubbo-SPI三种spi机制简要说明,这三种SPI的形式和特点各不相同。
在开发过程中遇到问题,一定不要放过,只要深入排查跟踪,才会有收获和进步。