[bs-178] Use OpenEntityManagerInView by default in webapp with JPA

If JPA is used and the context is a webapp we add the OEMIV interceptor.
It can be switched off by the user declaring a bean of type OEMSIVI or
the corresponding Filter, or by setting spring.jpa.open_in_view=false.

[Fixes #52939983]
This commit is contained in:
Dave Syer 2013-07-11 18:11:47 +01:00
parent 5b2986d7a9
commit 6dbd6d7c4c
5 changed files with 115 additions and 30 deletions

View File

@ -118,5 +118,10 @@
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -41,7 +41,7 @@ import org.springframework.util.StringUtils;
@Configuration
@ConditionalOnClass(HibernateEntityManager.class)
@EnableTransactionManagement
public class HibernateJpaAutoConfiguration extends JpaAutoConfiguration {
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DIALECTS;
static {

View File

@ -32,23 +32,32 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.bootstrap.context.condition.ConditionalOnBean;
import org.springframework.bootstrap.context.condition.ConditionalOnClass;
import org.springframework.bootstrap.context.condition.ConditionalOnExpression;
import org.springframework.bootstrap.context.condition.ConditionalOnMissingBean;
import org.springframework.bootstrap.context.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.Assert;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Base {@link EnableAutoConfiguration Auto-configuration} for JPA.
*
* @author Phillip Webb
* @author Dave Syer
*/
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
EnableTransactionManagement.class, EntityManager.class })
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EnableTransactionManagement.class,
EntityManager.class })
@ConditionalOnBean(DataSource.class)
public abstract class JpaAutoConfiguration implements BeanFactoryAware {
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@ -67,19 +76,33 @@ public abstract class JpaAutoConfiguration implements BeanFactoryAware {
return entityManagerFactoryBean;
}
@Configuration
@ConditionalOnWebApplication
@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
@ConditionalOnExpression("${spring.jpa.openInView:${spring.jpa.open_in_view:true}}")
protected static class JpaWebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
}
@Bean
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {
return new OpenEntityManagerInViewInterceptor();
}
}
/**
* Determines if the {@code dataSource} being used by Spring was created from
* {@link EmbeddedDatabaseConfiguration}.
* Determines if the {@code dataSource} being used by Spring was created from {@link EmbeddedDatabaseConfiguration}.
* @return true if the data source was auto-configured.
*/
protected boolean isAutoConfiguredDataSource() {
try {
BeanDefinition beanDefinition = this.beanFactory
.getBeanDefinition("dataSource");
return EmbeddedDatabaseConfiguration.class.getName().equals(
beanDefinition.getFactoryBeanName());
}
catch (NoSuchBeanDefinitionException ex) {
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("dataSource");
return EmbeddedDatabaseConfiguration.class.getName().equals(beanDefinition.getFactoryBeanName());
} catch (NoSuchBeanDefinitionException ex) {
return false;
}
}
@ -90,23 +113,19 @@ public abstract class JpaAutoConfiguration implements BeanFactoryAware {
protected DataSource getDataSource() {
try {
return this.beanFactory.getBean("dataSource", DataSource.class);
}
catch (RuntimeException ex) {
} catch (RuntimeException ex) {
return this.beanFactory.getBean(DataSource.class);
}
}
protected String[] getPackagesToScan() {
List<String> basePackages = AutoConfigurationUtils
.getBasePackages(this.beanFactory);
Assert.notEmpty(basePackages,
"Unable to find JPA packages to scan, please define "
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
List<String> basePackages = AutoConfigurationUtils.getBasePackages(this.beanFactory);
Assert.notEmpty(basePackages, "Unable to find JPA packages to scan, please define "
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
return basePackages.toArray(new String[basePackages.size()]);
}
protected void configure(
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
protected void configure(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
}
@Override

View File

@ -16,21 +16,29 @@
package org.springframework.autoconfigure.orm.jpa;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Test;
import org.springframework.autoconfigure.ComponentScanDetectorConfiguration;
import org.springframework.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
import org.springframework.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.autoconfigure.orm.jpa.test.City;
import org.springframework.bootstrap.TestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
/**
* Tests for {@link HibernateJpaAutoConfiguration}.
@ -39,11 +47,18 @@ import static org.junit.Assert.assertTrue;
*/
public class HibernateJpaAutoConfigurationTests {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
private ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
@After
public void close() {
if (context != null) {
context.close();
}
}
@Test
public void testEntityManagerCreated() throws Exception {
this.context.register(ComponentScanDetectorConfiguration.class,
((AnnotationConfigApplicationContext) this.context).register(ComponentScanDetectorConfiguration.class,
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
this.context.refresh();
@ -53,17 +68,58 @@ public class HibernateJpaAutoConfigurationTests {
@Test
public void testDataSourceTransactionManagerNotCreated() throws Exception {
this.context.register(ComponentScanDetectorConfiguration.class,
((AnnotationConfigApplicationContext) this.context).register(ComponentScanDetectorConfiguration.class,
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
DataSourceTransactionManagerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
TestConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(DataSource.class));
assertTrue(this.context.getBean("transactionManager") instanceof JpaTransactionManager);
}
@Test
public void testOpenEntityManagerInViewInterceptorCreated() throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(ComponentScanDetectorConfiguration.class, EmbeddedDatabaseConfiguration.class,
HibernateJpaAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
TestConfiguration.class);
this.context = context;
this.context.refresh();
assertNotNull(this.context.getBean(OpenEntityManagerInViewInterceptor.class));
}
@Test
public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenFilterPresent() throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(TestFilterConfiguration.class, ComponentScanDetectorConfiguration.class, EmbeddedDatabaseConfiguration.class,
HibernateJpaAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
this.context = context;
this.context.refresh();
assertEquals(0, this.context.getBeanNamesForType(OpenEntityManagerInViewInterceptor.class).length);
}
@Test
public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenExplicitlyOff() throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
TestUtils.addEnviroment(context, "spring.jpa.open_in_view:false");
context.register(TestConfiguration.class, ComponentScanDetectorConfiguration.class, EmbeddedDatabaseConfiguration.class,
HibernateJpaAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
this.context = context;
this.context.refresh();
assertEquals(0, this.context.getBeanNamesForType(OpenEntityManagerInViewInterceptor.class).length);
}
@ComponentScan(basePackageClasses = { City.class })
protected static class TestConfiguration {
}
@ComponentScan(basePackageClasses = { City.class })
@Configuration
protected static class TestFilterConfiguration {
@Bean
public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() {
return new OpenEntityManagerInViewFilter();
}
}
}

View File

@ -99,6 +99,11 @@
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>