不能@autowired存储库。 Bean循环引用

时间:2016-04-28 11:15:17

标签: java spring spring-boot

我的ApiConfig

@Configuration
@EnableConfigurationProperties(JpaProperties.class)
@EnableJpaRepositories("com.foo.api.persistence")
@ComponentScan("com.foo.api")
@PropertySource("classpath:application.yaml")
public class ApiConfig {

private static final Logger LOGGER = LogManager.getLogger();
private static final String MODEL_PACKAGE = "com.foo.api.model";

@Autowired
private MultiTenantConnectionProviderImpl multiTenantConnectionProvider;

@Autowired
private ApplicationContext applicationContext;

@Resource
private org.springframework.core.env.Environment env;

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws CurrentTenantIdentifierResolverException {
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setPackagesToScan(MODEL_PACKAGE);
    entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);

    Properties jpaProperties = new Properties();
    jpaProperties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
    jpaProperties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
    jpaProperties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, getCurrentTenantIdentifierResolver());
    jpaProperties.put(Environment.DIALECT, getHibernateDialect());

    entityManagerFactoryBean.setJpaProperties(jpaProperties);

    return entityManagerFactoryBean;
}

private CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() throws CurrentTenantIdentifierResolverException {
    CurrentTenantIdentifierResolver resolver = applicationContext.getBean(CurrentTenantIdentifierResolver.class);
    if (resolver == null) {
        throw new CurrentTenantIdentifierResolverException();
    }

    return resolver;
}

private String getHibernateDialect() {
    return env.getProperty(PropertyConstants.DIALECT);
}

}

但现在我不能@Autowired JpaRepository

    @Autowired
    private AgreementPersistence agreementPersistence;

协议持久性很简单,使用一个自己的基于查询的方法从JpaRepository扩展repo;

异常日志:

Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: 

Could not autowire field: AgreementPersistence agreementPersistence; nested exception is org.springframework.beans.factory.BeanCreationException: 

Error creating bean with name 'agreementPersistence': Cannot create inner bean '(inner bean)#38830ea' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: 

Error creating bean with name '(inner bean)#38830ea': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 

Error creating bean with name 'entityManagerFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?

如何解决? 也许我可以设置一些bean创建顺序或其他什么?

同时 我需要在另一个模块的配置类中使用@Autowired repo。

4 个答案:

答案 0 :(得分:3)

循环引用是指有两个bean,每个bean都注入另一个bean。

@Service
public class A {
    @Inject
    private B b;
}

@Service
public class B {
    @Inject
    private A a;
}

由于Spring无法注入未完全实例化的内容,因此在将A注入B之前,它无法将B注入A反之亦然,从而使Spring陷入困境。

在这些情况下,您应首先分析,看看是否确实需要循环依赖。也许将bean分解成这样的东西是你真正需要的:

@Service
public class C {
    @Inject
    private A a;
    @Inject
    private B b;
}

如果你无法解决问题,这是解决问题的一种方法:

@Service
public class A {
    @Inject
    private B b;
}

@Service
public class B extends ApplicationContextAware {
    //no inject
    private A a;

    private ApplicationContext applicationContext;

    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void handleDependencies() {
        this.a = applicationContext.getBean(A.class);
    }
}

答案 1 :(得分:1)

尝试将@Lazy添加到entityManagerFactoryAgreementPersistence(春天抱怨无法注入的课程)。

我相信它会阻止spring实际上尝试注入“spring-configured”bean,直到实际需要它为止。它应首先注入原始类以满足依赖性并在以后进行弹簧配置。

答案 2 :(得分:0)

您最终会多次初始化JPA存储库。试试这个:

 @ComponentScan(
    value = "com.foo.api",
    excludeFilters ={
            //@Repository beans are scanned and created by @EnableJpaRepositories already
            @ComponentScan.Filter(Repository.class)
    }

答案 3 :(得分:0)

在我的情况下,我在两个不同的模块中使用两个java配置类。 首先我编写自定义实体管理器工厂bean,在另一个我尝试自动连接我自己的持久性扩展JpaRepository。 在第二个配置类中,我创建自己的配置bean,我使用autowired repo。所以我有无法解决的循环参考。

我通过在我的配置bean中添加存储库参数来使用它,如下所示:

@Bean
Foo foo(RepoThatIWantToAutowired repo) { ... }

也许这对某人有帮助。