Service循环依赖

提问 2 3050
glen
glen 2019-04-11
版本:renren-fast Spring Boot2.1.3 开发环境:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sysLoginController': Unsatisfied dependency expressed through field 'sysUserService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'sysUserService': Bean with name 'sysUserService' has been injected into other beans [sysRoleService] 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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example. at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) at io.renren.RenrenApplication.main(RenrenApplication.java:19) Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'sysUserService': Bean with name 'sysUserService' has been injected into other beans [sysRoleService] 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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:622) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ... 19 common frames omitted
回帖
  • 我们本地启动,没有报异常
    0 回复
  • Chalvan
    2019-08-04
    的确存在循环依赖的问题。 SysUserServiceImpl中注入了SysRoleService的实例对象: [pre] @Autowired private SysRoleService sysRoleService; [/pre] 而SysUserRoleServiceImpl中又反向注入了SysUserService的实例对象: [pre] @Service("sysRoleService") public class SysRoleServiceImpl implements SysRoleService { @Autowired private SysRoleDao sysRoleDao; @Autowired private SysRoleMenuService sysRoleMenuService; @Autowired private SysUserRoleService sysUserRoleService; @Autowired private SysUserService sysUserService; …… } [/pre] spring 官方虽然不推荐使用循环依赖,但是也提供了setter注入的解决方案,感兴趣的同学可以参考,原文链接如下: a(https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html)[https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html] 我们此处提供另外一种方案。 回顾本例中的问题,其实SysUserRoleServiceImpl中引用SysRoleService的方法只有一处调用SysRoleDao对象的方法: [pre] //查询用户创建的角色列表 List<Long> roleIdList = sysRoleService.queryRoleIdList(user.getCreateUserId()); [/pre] 该方法在SysRoleServiceImpl实现类中的实现也比较简单,只是作为对外的接口代理调用了dao的方法: [pre] @Override public List<Long> queryRoleIdList(Long createUserId) { return sysRoleDao.queryRoleIdList(createUserId); } [/pre] 因为已经有Service层的保护,因此我们可以直接在SysUserRoleServiceImpl中注入SysRoleDao的对象,将其queryRoleIdList方法提上一层到SysUserService中调用即可,SysUserRoleServiceImpl中改造如下: [pre] @Service("sysUserService") public class SysUserServiceImpl implements SysUserService { @Autowired private SysUserDao sysUserDao; @Autowired private SysRoleDao sysRoleDao; …… /** * 检查角色是否越权 */ private void checkRole(SysUserEntity user){ //如果不是超级管理员,则需要判断用户的角色是否自己创建 if(user.getCreateUserId() == Constant.SUPER_ADMIN){ return ; } //查询用户创建的角色列表 List<Long> roleIdList = sysRoleDao.queryRoleIdList(user.getCreateUserId()); //判断是否越权 if(!roleIdList.containsAll(user.getRoleIdList())){ throw new RRException("新增用户所选角色,不是本人创建"); } } } [/pre]
    0 回复