zoukankan      html  css  js  c++  java
  • SpringBoot

    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;
    	}
    

      

  • 相关阅读:
    CPSR_cxsf
    C的xml编程libxml2(转)
    showModalDialog 使用详解
    SecureCRT 6.7.4 安装
    Nokia Qt SDK 1.1的开发环境的搭建
    ARM寄存器介绍
    ucos在xp平台下开发环境搭建
    用JavaScript实现让浏览器停止载入页面
    makefile变量使用及其条件判断
    Makefile中指示符“include”、“include”和“sinclude”的区别
  • 原文地址:https://www.cnblogs.com/jianyi0115/p/13861151.html
Copyright © 2011-2022 走看看