2016-04-28 21 views
1

ApiConfig不能@autowired存儲庫。豆循環引用

@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); 
} 

}

但現在我無法@AutowiredJpaRepository

@Autowired 
    private AgreementPersistence agreementPersistence; 

協議的持久性是簡單的回購從JpaRepository擴展了一個自己的基於查詢的方法;

異常日誌:

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回購在另一個模塊的配置類。

+0

請將Spring初始化錯誤堆棧添加到您的問題中,以便更清楚「@Autowired」注入會出錯。 –

+0

嘗試調用entityManagerFactoryBean.afterPropertiesSet()方法 – shazin

+0

它看起來像你試圖將'AgreementPersistence'自動裝入一個負責配置JPA的類。你能分享你的'@ Configuration'類的更多細節嗎? –

回答

0

在我的情況下,我在兩個不同的模塊中使用兩個java配置類。 在我第一次編寫自定義實體管理器工廠bean,在另一個我嘗試自動裝配我自己的持久性擴展JpaRepository。 在第二個配置類中,我創建自己的配置bean,我使用autowired回購。所以我有無法解析的循環參考。

我加入資料庫的說法在我的配置豆這樣使用它:

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

也許它可以幫助的人。

0

您最終正在初始化您的JPA存儲庫多次。試試這個:

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

+0

它沒有幫助; 我想我彈簧時嘗試autowired回購與內部bean EntityManager,當EntityManagerFactory創建時出現問題; – DamienMiheev

2

循環引用是當你有兩個豆,每注入等。

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

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

由於春節不能注入的東西沒有被完全實例化,它不能B之前注入到AB注入A,反之亦然,從而使彈簧卡住。

在這些情況下,您應該先分析一下,看看是否真的需要循環依賴。也許分解豆​​成這樣的事情是你真正需要的:

@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); 
    } 
} 
+0

我仍然有同樣的問題。 我在模塊1(組件掃描「com.foo.mod1」,其中我初始化entityManagerFactoryBean; 此外,我也conf2在模塊2(組件掃描「com.foo.mod2」; Module2編譯依賴模塊到模塊1 build.gradle ; 在conf2中I @Import(Conf1.class); 但是當我試圖從appCtx獲取bean時,我有同樣的異常 – DamienMiheev

1

嘗試給entityManagerFactoryAgreementPersistence加上@Lazy(春天抱怨不能注射的類)。

我相信它會阻止spring實際上試圖注入「彈簧配置」bean直到它實際需要。它應該首先注入原始類以滿足依賴性,並在稍後進行彈性配置。

+0

這解決了我的問題,謝謝。 –