Ich hatte eine funktionierende Jersey 2.2 Applikation mit Spring 4, in der ich Eclipselink als JPA-Implementierung verwendete.Spring 4 @Konfigurationsreihenfolge zum Einrichten von JPA
Die Anwendung Config calss sieht wie folgt aus:
@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);
}
}
Die PPV Konfigurationsklasse:
@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;
}
}
Nun, das funktioniert gut. Beim Start wird die Anwendungskonfigurationsklasse FIRST geladen, so dass "PropertySourcesPlaceholderConfigurer" registriert wird und ich @Value (...) Annotationen in der jpa config-Klasse verwenden kann, die als SECOND geladen wird.
Heute habe ich entschieden, dass ich Eclipselink wegen seiner Auditing-Fähigkeiten durch Hibernate ersetzen werde.
Um pom.xml Ich habe hinzugefügt:
<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>
und haben JPA Config-Klasse geändert:
@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;
}
}
Nun zu meiner Überraschung, Last/Ausführungs Reihenfolge der Anwendung config und JPA Config Klassen haben ausgetauscht, so dass jpa config zuerst geladen wird und dann die Anwendungskonfiguration SECONDD, was dazu führt, dass "PropertySourcesPlaceholderConfigurer" nicht bei der Ladezeit der jpa config Klasse registriert wird, also funktionieren @value Annotationen nicht!
Ich bin wirklich interessiert zu wissen, warum ist das so? Warum wurde die Ausführungsreihenfolge getauscht?
Ich weiß, dass ich es nicht erklären JPA Config calass als @Configuration Trick kann und es einfach wie eine Bohne in Anwendung Config-Klasse registrieren wie:
@Bean
public JPAConfig setUpJpaHibernate() {
return new JPAConfig();
}
Aber noch, ich möchte wissen, was ist passiert hier?
Es gibt keine Informationen darüber, wie die Spring-Anwendung bootstrappt wird. Normalerweise liest Feder alle Konfigurationen, erstellt einen Abhängigkeitsbaum und instanziiert zuerst die Blattknoten. Wenn es keinen Bezug zwischen Ihren zwei Konfigurationen gibt, gibt es nichts, um Spring zu sagen, in welcher Reihenfolge es instanziiert werden soll (Sie sollten also die Reihenfolge zufällig betrachten). Es gibt spezielle Regeln für PropertyConfiguration, zum Beispiel, wenn Sie einen 'PropertyPlaceholderConfigurer' haben, muss die vorhandene Definition eine statische Methode sein. Also würde ich @PropertySource immer in die Bootstrapped-Konfiguration setzen. –
naja, im Grunde hast du meine Frage nicht beantwortet und keine Lösung geliefert. Ich habe zwei Teile Code, die sich anders verhalten. Ich muss sicherstellen, dass die Klasse, die RecourceConfig lädt, zuerst geladen wird, da hier die App-Konfiguration stattfindet. – greengold
Normalerweise würde ich nur den Spring-Code debuggen, um herauszufinden, warum das passiert. Aus irgendeinem Grund bewirkt die Abhängigkeitsauflösung in Spring, dass Ihre 'JPAConfig' vor der Config verarbeitet wird, die' ResourceConfig' erweitert, normalerweise würde dies auf eine Abhängigkeit zwischen den beiden zurückzuführen sein, oder wenn sie beide Blattkonfigurationen sind, ist die Reihenfolge 'zufällig' ". Persönlich bin ich eher neugierig, welches Problem Jersey löst, das Spring MVC nicht, und warum das Auditing in EclipseLink nicht gut genug ist? –