我在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();
}
但儘管如此,我想知道,是什麼在這裏發生?
沒有關於如何啓動Spring應用程序的信息?通常,spring會讀取所有配置,構建依賴樹並首先實例化葉節點。如果你的兩個配置之間沒有引用,那麼Spring就沒有什麼可以告訴它應該實例化它們的順序(所以你應該考慮隨機順序)。對於ProperyConfiguration有特殊的規則,例如,如果你有一個'PropertyPlaceholderConfigurer'的定義必須是一個靜態方法。所以我總是把@PropertySource放在引導配置中。 –
基本上,你沒有回答我的問題,也沒有提供解決方案。我有兩段代碼行爲不同。我需要確保首先擴展RecourceConfig的類,因爲這是應用程序配置發生的地方。 – greengold
通常我只是調試Spring代碼來找出爲什麼發生這種情況。出於某種原因,Spring中的依賴關係解析會導致您的'JPAConfig'在擴展'ResourceConfig'的Config之前被處理,通常這是由於兩者之間的依賴關係,或者它們都是葉子配置,順序是'random 」。就我個人而言,我更關心Jersey解決哪個問題,Spring MVC沒有,以及爲什麼EclipseLink中的審計不夠好? –