mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
[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:
parent
5b2986d7a9
commit
6dbd6d7c4c
@ -118,5 +118,10 @@
|
|||||||
<artifactId>spring-test</artifactId>
|
<artifactId>spring-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jdk14</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -41,7 +41,7 @@ import org.springframework.util.StringUtils;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(HibernateEntityManager.class)
|
@ConditionalOnClass(HibernateEntityManager.class)
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
public class HibernateJpaAutoConfiguration extends JpaAutoConfiguration {
|
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
|
||||||
|
|
||||||
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DIALECTS;
|
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DIALECTS;
|
||||||
static {
|
static {
|
||||||
|
@ -32,23 +32,32 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.bootstrap.context.condition.ConditionalOnBean;
|
import org.springframework.bootstrap.context.condition.ConditionalOnBean;
|
||||||
import org.springframework.bootstrap.context.condition.ConditionalOnClass;
|
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.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
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.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
import org.springframework.util.Assert;
|
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.
|
* Base {@link EnableAutoConfiguration Auto-configuration} for JPA.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
|
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EnableTransactionManagement.class,
|
||||||
EnableTransactionManagement.class, EntityManager.class })
|
EntityManager.class })
|
||||||
@ConditionalOnBean(DataSource.class)
|
@ConditionalOnBean(DataSource.class)
|
||||||
public abstract class JpaAutoConfiguration implements BeanFactoryAware {
|
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
|
||||||
|
|
||||||
private ConfigurableListableBeanFactory beanFactory;
|
private ConfigurableListableBeanFactory beanFactory;
|
||||||
|
|
||||||
@ -67,19 +76,33 @@ public abstract class JpaAutoConfiguration implements BeanFactoryAware {
|
|||||||
return entityManagerFactoryBean;
|
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
|
* Determines if the {@code dataSource} being used by Spring was created from {@link EmbeddedDatabaseConfiguration}.
|
||||||
* {@link EmbeddedDatabaseConfiguration}.
|
|
||||||
* @return true if the data source was auto-configured.
|
* @return true if the data source was auto-configured.
|
||||||
*/
|
*/
|
||||||
protected boolean isAutoConfiguredDataSource() {
|
protected boolean isAutoConfiguredDataSource() {
|
||||||
try {
|
try {
|
||||||
BeanDefinition beanDefinition = this.beanFactory
|
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("dataSource");
|
||||||
.getBeanDefinition("dataSource");
|
return EmbeddedDatabaseConfiguration.class.getName().equals(beanDefinition.getFactoryBeanName());
|
||||||
return EmbeddedDatabaseConfiguration.class.getName().equals(
|
} catch (NoSuchBeanDefinitionException ex) {
|
||||||
beanDefinition.getFactoryBeanName());
|
|
||||||
}
|
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,23 +113,19 @@ public abstract class JpaAutoConfiguration implements BeanFactoryAware {
|
|||||||
protected DataSource getDataSource() {
|
protected DataSource getDataSource() {
|
||||||
try {
|
try {
|
||||||
return this.beanFactory.getBean("dataSource", DataSource.class);
|
return this.beanFactory.getBean("dataSource", DataSource.class);
|
||||||
}
|
} catch (RuntimeException ex) {
|
||||||
catch (RuntimeException ex) {
|
|
||||||
return this.beanFactory.getBean(DataSource.class);
|
return this.beanFactory.getBean(DataSource.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String[] getPackagesToScan() {
|
protected String[] getPackagesToScan() {
|
||||||
List<String> basePackages = AutoConfigurationUtils
|
List<String> basePackages = AutoConfigurationUtils.getBasePackages(this.beanFactory);
|
||||||
.getBasePackages(this.beanFactory);
|
Assert.notEmpty(basePackages, "Unable to find JPA packages to scan, please define "
|
||||||
Assert.notEmpty(basePackages,
|
|
||||||
"Unable to find JPA packages to scan, please define "
|
|
||||||
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
|
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
|
||||||
return basePackages.toArray(new String[basePackages.size()]);
|
return basePackages.toArray(new String[basePackages.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void configure(
|
protected void configure(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
|
||||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -16,21 +16,29 @@
|
|||||||
|
|
||||||
package org.springframework.autoconfigure.orm.jpa;
|
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 javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.autoconfigure.ComponentScanDetectorConfiguration;
|
import org.springframework.autoconfigure.ComponentScanDetectorConfiguration;
|
||||||
import org.springframework.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
import org.springframework.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||||
import org.springframework.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
import org.springframework.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||||
import org.springframework.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
|
import org.springframework.autoconfigure.jdbc.EmbeddedDatabaseConfiguration;
|
||||||
import org.springframework.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
|
||||||
import org.springframework.autoconfigure.orm.jpa.test.City;
|
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.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
|
||||||
import static org.junit.Assert.assertTrue;
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link HibernateJpaAutoConfiguration}.
|
* Tests for {@link HibernateJpaAutoConfiguration}.
|
||||||
@ -39,11 +47,18 @@ import static org.junit.Assert.assertTrue;
|
|||||||
*/
|
*/
|
||||||
public class HibernateJpaAutoConfigurationTests {
|
public class HibernateJpaAutoConfigurationTests {
|
||||||
|
|
||||||
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
private ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void close() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEntityManagerCreated() throws Exception {
|
public void testEntityManagerCreated() throws Exception {
|
||||||
this.context.register(ComponentScanDetectorConfiguration.class,
|
((AnnotationConfigApplicationContext) this.context).register(ComponentScanDetectorConfiguration.class,
|
||||||
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
|
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
|
||||||
PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
@ -53,17 +68,58 @@ public class HibernateJpaAutoConfigurationTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDataSourceTransactionManagerNotCreated() throws Exception {
|
public void testDataSourceTransactionManagerNotCreated() throws Exception {
|
||||||
this.context.register(ComponentScanDetectorConfiguration.class,
|
((AnnotationConfigApplicationContext) this.context).register(ComponentScanDetectorConfiguration.class,
|
||||||
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
|
EmbeddedDatabaseConfiguration.class, HibernateJpaAutoConfiguration.class,
|
||||||
DataSourceTransactionManagerAutoConfiguration.class,
|
DataSourceTransactionManagerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
|
||||||
PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
TestConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
assertNotNull(this.context.getBean(DataSource.class));
|
assertNotNull(this.context.getBean(DataSource.class));
|
||||||
assertTrue(this.context.getBean("transactionManager") instanceof JpaTransactionManager);
|
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 })
|
@ComponentScan(basePackageClasses = { City.class })
|
||||||
protected static class TestConfiguration {
|
protected static class TestConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ComponentScan(basePackageClasses = { City.class })
|
||||||
|
@Configuration
|
||||||
|
protected static class TestFilterConfiguration {
|
||||||
|
@Bean
|
||||||
|
public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() {
|
||||||
|
return new OpenEntityManagerInViewFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,11 @@
|
|||||||
<artifactId>jcl-over-slf4j</artifactId>
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jdk14</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
Loading…
Reference in New Issue
Block a user