2017-04-07 121 views
0

我在Spring 4中使用了Jersey 2.2的應用程序,其中我使用Eclipselink作爲JPA實現。Spring 4 @設置配置順序JPA

應用程序配置CALSS如下所示:

@Configuration 
@ComponentScan(value = "com.nws.vedica", lazyInit = true) 
@PropertySource({"classpath:swagger.properties", "classpath:vedica.properties"}) 
@ApplicationPath("/api") 

public class VedicaConfig extends ResourceConfig { 

public VedicaConfig() { 
    packages("com.nws.vedica"); 
    property(ServletProperties.FILTER_FORWARD_ON_404, true); 
    register(MultiPartFeature.class); 
    register(JacksonFeature.class); 
    register(ValidationFeature.class); 
    register(ValidationConfigurationContextResolver.class); 
    register(PropertySourcesPlaceholderConfigurer.class); 

    register(ApiListingResource.class); 
    register(SwaggerSerializers.class); 
} 
} 

JPA配置類:

@Configuration 
@EnableTransactionManagement 
public class JPAConfig { 

private Map<String, String> properties; 

@Value("${db.url}") 
private String dbConnectionURL; 

@Value("${db.user}") 
private String dbUser; 

@Value("${db.pass}") 
private String dbPassword; 

@PostConstruct 
public void init() { 
    properties = new HashMap<>(); 
    properties.put("javax.persistence.jdbc.url", dbConnectionURL); 
    properties.put("javax.persistence.jdbc.user", dbUser); 
    properties.put("javax.persistence.jdbc.password", dbPassword); 
    properties.put("javax.persistence.jdbc.driver", "org.postgresql.Driver"); 
    properties.put("javax.persistence.target-database", "PostgreSQL"); 
    properties.put("eclipselink.cache.shared.default", "true"); 
    properties.put("eclipselink.ddl-generation", "none"); 
    properties.put("eclipselink.logging.level.sql", "fine"); 
    properties.put("eclipselink.logging.parameters", "true"); 
    properties.put("eclipselink.deploy-on-startup", "true"); 
    properties.put("eclipselink.ddl-generation.output-mode", "database"); 
} 

@Bean 
public JpaTransactionManager jpaTransMan(){ 
    JpaTransactionManager jtManager = new JpaTransactionManager(
      getEntityManagerFactoryBean().getObject()); 
    return jtManager; 
} 

@Bean 
public LocalEntityManagerFactoryBean getEntityManagerFactoryBean() { 
    LocalEntityManagerFactoryBean lemfb = new LocalEntityManagerFactoryBean(); 
    lemfb.setJpaPropertyMap(properties); 
    lemfb.setPersistenceUnitName(Vedantas.PU_NAME); 
    lemfb.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); 
    return lemfb; 
} 
} 

現在,這個效果很好。在啓動時,應用程序配置類被加載FIRST,所以「PropertySourcesPlaceholderConfigurer」得到註冊,我可以在jpa配置類中使用@Value(...)註釋,它被加載爲SECOND。

今天我決定用Hibernate替換Eclipselink,因爲它具有審計功能。

要pom.xml中我已經加入:

<dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-core</artifactId> 
     <version>5.2.9.Final</version> 
    </dependency> 

    <dependency> 
     <groupId>org.hibernate.javax.persistence</groupId> 
     <artifactId>hibernate-jpa-2.1-api</artifactId> 
     <version>1.0.0.Final</version> 
    </dependency> 


    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-envers</artifactId> 
     <version>5.2.9.Final</version> 
    </dependency> 

,並改變了JPA配置類:現在

@Configuration 
@EnableTransactionManagement 
public class JPAConfig { 

private Map<String, String> properties; 

@Value("${db.url}") 
private String dbConnectionURL; 

@Value("${db.user}") 
private String dbUser; 

@Value("${db.pass}") 
private String dbPassword; 

@PostConstruct 
public void init() { 
    properties = new HashMap<>(); 
    properties.put("javax.persistence.jdbc.url", dbConnectionURL); 
    properties.put("javax.persistence.jdbc.user", dbUser); 
    properties.put("javax.persistence.jdbc.password", dbPassword); 
    properties.put("javax.persistence.jdbc.driver", "org.postgresql.Driver"); 
    properties.put("javax.persistence.target-database", "PostgreSQL"); 
    properties.put("hibernate.hbm2ddl.auto", "create"); 
    properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); 
} 

@Bean 
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){ 
    JpaTransactionManager transactionManager = new JpaTransactionManager(); 
    transactionManager.setEntityManagerFactory(emf); 

    return transactionManager; 
} 

@Bean 
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ 
    return new PersistenceExceptionTranslationPostProcessor(); 
} 

@Bean 
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
    em.setPackagesToScan(new String[]{"com.nws.vedica.model"}); 
    em.setPersistenceUnitName(Vedantas.PU_NAME); 

    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
    em.setJpaVendorAdapter(vendorAdapter); 
    em.setJpaPropertyMap(properties); 

    return em; 
} 
} 

,出乎我的意料,負載/執行應用程序配置和JPA配置的順序類已經交換,因此jpa config正在加載FIRST,然後導致「PropertySourcesPlaceholderConfigurer」未在jpa config class加載時註冊的應用程序配置SECONDLY,所以@value註釋不起作用!

我真的很想知道爲什麼是這樣嗎?爲什麼交換執行順序?

我知道我可以通過不聲明JPA配置calass作爲@Configuration欺騙它,只是把它註冊爲應用程序配置類像一個bean:

@Bean 
    public JPAConfig setUpJpaHibernate() { 
     return new JPAConfig(); 
    } 

但儘管如此,我想知道,是什麼在這裏發生?

+0

沒有關於如何啓動Spring應用程序的信息?通常,spring會讀取所有配置,構建依賴樹並首先實例化葉節點。如果你的兩個配置之間沒有引用,那麼Spring就沒有什麼可以告訴它應該實例化它們的順序(所以你應該考慮隨機順序)。對於ProperyConfiguration有特殊的規則,例如,如果你有一個'PropertyPlaceholderConfigurer'的定義必須是一個靜態方法。所以我總是把@PropertySource放在引導配置中。 –

+0

基本上,你沒有回答我的問題,也沒有提供解決方案。我有兩段代碼行爲不同。我需要確保首先擴展RecourceConfig的類,因爲這是應用程序配置發生的地方。 – greengold

+0

通常我只是調試Spring代碼來找出爲什麼發生這種情況。出於某種原因,Spring中的依賴關係解析會導致您的'JPAConfig'在擴展'ResourceConfig'的Config之前被處理,通常這是由於兩者之間的依賴關係,或者它們都是葉子配置,順序是'random 」。就我個人而言,我更關心Jersey解決哪個問題,Spring MVC沒有,以及爲什麼EclipseLink中的審計不夠好? –

回答

0

訂單更改的原因是將JPA導入到JPAConfig類的PersistenceExceptionTranslationPostProcessor bean中。

@Bean 
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ 
    return new PersistenceExceptionTranslationPostProcessor(); 
} 

將此移至VedicaConfig類可爲我解決問題。