使用 Java Streams 和 Spring Boot 的 RESTful Web 服务
Posted
技术标签:
【中文标题】使用 Java Streams 和 Spring Boot 的 RESTful Web 服务【英文标题】:RESTful webservice using Java Streams and Spring Boot 【发布时间】:2020-07-08 15:10:07 【问题描述】:我尝试实现一个 RESTful WebService,它能够直接从数据库中流式传输数百万条记录。 我正在使用 SpringBoot 2.2.5、Hibernate 5 和 PostgreSQL 11
根据这篇文章: https://www.airpair.com/java/posts/spring-streams-memory-efficiency
需要一步将标志“allowResultAccessAfterCompletion”设置为真。 但是如何在 Spring Boot 中做到这一点?
到目前为止,我的应用程序中没有任何 SessionFactory、EntityManagerFactory、Datasource 等配置。一切都由 SpringBoot 自动配置。
如果我在下面添加建议的配置,应用程序将无法启动,因为缺少 SessionFactory。
@Configuration
@EnableTransactionManagement
public class DataConfig
@Autowired @Bean
public PlatformTransactionManager txManager(SessionFactory sf)
HibernateTransactionManager mgr = new HibernateTransactionManager(sf);
mgr.setAllowResultAccessAfterCompletion(true);
return mgr;
... (the rest of your data config, including the LocalSessionFactoryBean) ...
如果我通过从 EntityManagerFactory 解包来提供 SessionFactory bean,我会得到另一个异常:
通过字段 'entityManagerFactory' 表达的不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCurrentlyInCreationException:创建名为“getSessionFactory”的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?
有人对我的设置有有效的配置吗?
这个标志不能简单地由 application.properties 中的一些配置值设置吗?
谢谢!
【问题讨论】:
你的 pom.xml 中是否添加了spring-boot-starter-data-jpa
maven 依赖项?还在application.properties
/application.yml
中添加适当的密钥(驱动程序类名称、用户名、密码、url)
【参考方案1】:
首先,您需要确定您的项目是否需要使用 Hibernate 或 Spring JPA。使用框架而不是反对它。今天大多数人更喜欢使用 jpa 类而不是 hibernate 类。
由于您使用的是 springboot ,因此最好的方法是使用框架并使用 spring-boot-starter-data-jpa
,它将在启动时自动配置所有必要的 bean。在这种情况下,您可以提供自己的自定义 bean 来根据需要覆盖参数。
在您在问题中提供的示例代码中,您直接使用 Hibernate 类,因此您必须手动创建所有必要的 bean,因为除非您禁用自动配置可能会导致您出现循环依赖问题。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.sample.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
@Autowired
Environment environment;
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory()
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.sample.spring");
lfb.setJpaProperties(hibernateProps());
return lfb;
@Bean
DataSource dataSource()
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
Properties hibernateProps()
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
@Bean
JpaTransactionManager transactionManager()
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
【讨论】:
嗨,我使用的是 spring-boot-starter-data-jpa 并且不直接使用任何 Hibernate 类。使用 Spring Boot 自动配置一切运行良好。我不想禁用它。问题是,我必须将 HibernateTransactionManager 类的属性“allowResultAccessAfterCompletion”设置为 true。【参考方案2】:您也可以很好地提供自己的 SessionFactory,在这种情况下,spring boot 不会为您创建另一个。以下是Bootstrapping Hibernate 5 with Spring article的摘录,请根据您的需要随意调整
@Configuration
@EnableTransactionManagement
public class HibernateConf
@Bean
public LocalSessionFactoryBean sessionFactory()
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
"com.baeldung.hibernate.bootstrap.model" );
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
@Bean
public DataSource dataSource()
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("sa");
return dataSource;
@Bean
public PlatformTransactionManager hibernateTransactionManager()
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setAllowResultAccessAfterCompletion(true);
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
private final Properties hibernateProperties()
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "create-drop");
hibernateProperties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.H2Dialect");
return hibernateProperties;
如果您知道 Spring Boot 已经在其自己的生命周期中创建了 HibernateTransactionManager,则另一种方法是使用 BeanPostProcessor。以下是这个 BeanPostProcessor 的轮廓
public class HTMPostProcessor implements BeanPostProcessor
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException
if (bean instanceof HibernateTransactionManager)
((HibernateTransactionManager)bean).setAllowResultAccessAfterCompletion(true);
return bean; // you can return any other object as well
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException
return bean; // you can return any other object as well
希望这会有所帮助!
【讨论】:
嗨,尝试了使用 BeanPostProcessor 的方法。但是,如果我使用 JPA,似乎我没有 HibernateTransactionManger。 JpaTransactionManager 已被实例化,但我无法设置所需的标志。以上是关于使用 Java Streams 和 Spring Boot 的 RESTful Web 服务的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud Streams 没有在消息中设置 kafka 键?
使用 JDK8 和 lambda (java.util.stream.Streams.zip) 压缩流