我在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中的审计不够好? –