关于Springboot+MybatisPlus架构循环依赖问题研究
由于公司产品在做架构设计之初,考虑到微服务可拆可合,即为部署时需支持单体部署与分布式微服务部署两种模式。日常都是微服务测试,产品1.0版本基本开发完成后,做单体部署时发现较多循环依赖问题。一开始以一种简单可行的办法进行了解决,就是加个@Lazy注解。最近在上架构课时,发现其实Spring对循环依赖在底层有一套很好的解决方案,就是将bean的初始化做了三层缓存设计。然后就想到了我们为啥还会遇到循环依赖的问题,需要一个个地方手动处理?于是借此,花了点时间深入研究了下。
错误日志信息:
03-12 17:28:43.519 [main] INFO o.s.b.a.endpoint.web.ServletEndpointRegistrar:74 -> Registered '/actuator/hystrix.stream' to hystrix.stream-actuator-endpoint
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.4.1
03-12 17:28:45.894 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext:558 -> Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoGoodsController': Unsatisfied dependency expressed through field 'homeService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'homeServiceImpl': Bean with name 'homeServiceImpl' has been injected into other beans [userServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
03-12 17:28:45.898 [main] WARN o.s.c.a.AnnotationConfigApplicationContext:1013 -> Exception thrown from ApplicationListener handling ContextClosedEvent
org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'rabbitConnectionFactory': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:220)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:319)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
网上寻找原因
- 有不少人说是由于系统中用到了Spring的异步调用机制所致
- 也就是EnableAsync 这个,其实我们就部分服务用到,没有开启或用到的服务也一样会出现此类问题
- 接着找啊找,也没找到具体原因,找到的都是解决方案;
- 于是我建了一个简单的Springboot工程,写了一套带有循环依赖service,发现并没有问题
- 将待循环依赖的一套service移入公司产品中,启动和运行也正常;
- 此刻,关注到了错误信息里有一条
but has eventually been wrapped
- 突然想起来可能和Service用到了MybatisPlus特性有关,因为我们的Service是集成了BaseServiceImpl
- 于是将Service接口和实现都加上Mp的继承特性,问题就报错来了。
public interface IHomeService extends IBaseService<DemoGoods> {
}
@Service
public class DemoGoodsServiceImpl extends BaseServiceImpl<DemoGoodsMapper, DemoGoods> implements IDemoGoodsService {
}
简单总结
- 用了MP以后,看来这个问题就不好解决了,感觉service由于集成了MP的基类,算是被Spring认为是包装过的类
- 这种情况下,暂时没有更好的解决方案,只能@Lazy了
- 或者抽象出来一个中间Service,避免循环依赖
- 又或者给Service注入加上一个Set方法,让他通过set方法注入?
- 总而言之,都不如一个注解来的直接,那就这样吧