2017-04-07 61 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类可为我解决问题。