open-in-view功能是指SpringBoot在请求开始前自动初始化一个数据库会话,一般是EntityManager。
当这个功能启用时,会输出一条日志:
2020-10-22 20:46:46.720 WARN 6484 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
-----open-in-view功能的启动条件是:
1) 引用spring-boot-starter-jpa
2)或者引用spring-boot-starter-jdbc + hibernate
3)或者,直接引用hibernate + spring-orm
----这个功能的启用过程:
1)在spring-boot-autoconfigure包中,META-INF/Spring.factories 文件配置了启动类:
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
HibernateJpaAutoConfiguration:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
@EnableConfigurationProperties(JpaProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
@Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
}
从这个类的Condition条件可以看出其启用条件:‘
当前classpath下要有LocalContainerEntityManagerFactoryBean类,这个类在org.springframework.orm.jpa包下,所以要引用spring-orm
EntityManager在javax.persistence下,SessionImplementor 是Hibernate的类
2)HibernateJpaAutoConfiguration引入了HibernateJpaConfiguration,HibernateJpaConfiguration的启用条件是当前仅有一个DataSource bean
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HibernateProperties.class)
@ConditionalOnSingleCandidate(DataSource.class)
class HibernateJpaConfiguration extends JpaBaseConfiguration {
HibernateJpaConfiguration的基类JpaBaseConfiguration定义了一个内部类
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(WebMvcConfigurer.class)
@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
@ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)
@ConditionalOnProperty(prefix = "spring.jpa", name = "open-in-view", havingValue = "true", matchIfMissing = true)
protected static class JpaWebConfiguration {
private static final Log logger = LogFactory.getLog(JpaWebConfiguration.class);
private final JpaProperties jpaProperties;
protected JpaWebConfiguration(JpaProperties jpaProperties) {
this.jpaProperties = jpaProperties;
}
@Bean
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {
if (this.jpaProperties.getOpenInView() == null) {
logger.warn("spring.jpa.open-in-view is enabled by default. "
+ "Therefore, database queries may be performed during view "
+ "rendering. Explicitly configure spring.jpa.open-in-view to disable this warning");
}
return new OpenEntityManagerInViewInterceptor();
}
@Bean
public WebMvcConfigurer openEntityManagerInViewInterceptorConfigurer(
OpenEntityManagerInViewInterceptor interceptor) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addWebRequestInterceptor(interceptor);
}
};
}
}
这个类注册了OpenEntityManagerInViewInterceptor 拦截器。OpenEntityManagerInViewInterceptor 用来在请求启动前初始化EntityManager,在请求完成后关闭EntityManager
JpaBaseConfiguration 会自动创建一个事务管理器和EntityManagerFactory. OpenEntityManagerInViewInterceptor默认会采用这个EntityManagerFactory类创建EntityManager
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
public PlatformTransactionManager transactionManager(
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
@Bean
@Primary
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) {
Map<String, Object> vendorProperties = getVendorProperties();
customizeVendorProperties(vendorProperties);
return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan()).properties(vendorProperties)
.mappingResources(getMappingResources()).jta(isJta()).build();
}
------------------------
LocalContainerEntityManagerFactoryBean 依赖DataSource,DataSourde的创建过程:
META-INF/Spring.factories 文件配置了启动类:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
DataSourceAutoConfiguration 的启用条件是,当前类路径下存在DataSource(框架类)和org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType,EmbeddedDatabaseType是spring-jdbc下的类
所以,只要引用spring-jdbc包,DataSource自动初始话过程就会启用。注意:spring-orm包引用了spring-jdbc。
DataSourceAutoConfiguration按照顺序,如果当前存在签入数据库引用,则创建签入数据源, 否侧尝试创建Hikari/Tomcat/Dbcp2/OracleUcp 等连接池类型的数据源
-----------
只要项目引用了hibernate,spring-orm, 并且当前容器中只有一个DataSource bean, 这个open-in-view默认会启用,如果需要禁用,则要显示设置 spring.jpa.open-in-view=false
-----------
可以在代码中设置spring.jpa.open-in-view默认值:
public static void main(String[] args) {
new SpringApplicationBuilder(DemoApplication.class)
.properties(props())
.build()
.run(args);
//SpringApplication.run(DemoApplication.class, args);
}
private static Properties props() {
Properties properties = new Properties();
properties.setProperty("spring.jpa.open-in-view", "false");
return properties;
}
浙公网安备 33010602011771号