Spring Boot 2.0.0 循环bean依赖EntityManger和SessionFactory
Posted
技术标签:
【中文标题】Spring Boot 2.0.0 循环bean依赖EntityManger和SessionFactory【英文标题】:Spring Boot 2.0.0 cycle bean dependency EntityManger and SessionFactory 【发布时间】:2018-09-21 17:38:31 【问题描述】:我对新的 Spring Boot 版本 2.0.0 有疑问。 我需要创建 SessionFactory bean,为此我需要 Spring 来注入 EntityManager。
package cz.moravec;
import cz.moravec.provisioning.Provisioner;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceUnit;
@SpringBootApplication
@EntityScan("cz.moravec.data")
public class Main
// @Bean
// public CountryDao countryDao()
// return new CountryDao();
//
//
// @Bean
// public TownDao townDao()
// return new TownDao();
//
@Autowired
@Bean
@Transactional
public SessionFactory sessionFactory(EntityManager entityManager)
Session session = entityManager.unwrap(Session.class);
return session.getSessionFactory();
@Profile("devel", "test")
@Bean(initMethod = "doProvision")
public Provisioner provisioner()
return new Provisioner();
public static void main(String[] args)
SpringApplication app = new SpringApplication(Main.class);
ApplicationContext ctx = app.run(args);
// CountryDao countryDao = ctx.getBean(CountryDao.class);
// List<Country> countries = countryDao.getCountries();
// UsersDao usersDao = ctx.getBean(UsersDao.class);
//
// List<User> users = usersDao.getAllUsers();
// System.out.println(users);
此代码在使用 Spring Boot 1.5.11.RELEASE 时有效。但不适用于 Spring Boot 2.0.0.RELEASE。
当我运行代码时,由于循环依赖,没有创建 ApplicationContext。
控制台有输出。
19:44:31.282 [main] WARN o.s.c.a.AnnotationConfigApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sessionFactory' defined in cz.moravec.Main: Unsatisfied dependency expressed through method 'sessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.orm.jpa.SharedEntityManagerCreator#0': Cannot resolve reference to bean 'sessionFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'sessionFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?
Disconnected from the target VM, address: '127.0.0.1:11537', transport: 'socket'
19:44:31.286 [main] INFO o.s.b.a.l.ConditionEvaluationReportLoggingListener -
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
19:44:31.288 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| sessionFactory defined in cz.moravec.Main
↑ ↓
| org.springframework.orm.jpa.SharedEntityManagerCreator#0
└─────┘
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.moravec</groupId>
<artifactId>semester_project</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
【问题讨论】:
为什么是@Transactional
这个方法?你到底为什么要得到EntityManager
得到Session
得到SessioNFactory
。如果有一种复杂的方法可以获取SessionFactory
,那就是它,我真的很惊讶它甚至可以工作。而是注入EntityManagerFactory
并将其解包到SessionFactory
。
没有@Transactional 我得到Hibernate 无法解开接口org.hibernate.SessionFactory,
好吧,这行得通,我以前确实有过这样的情况,但我正在尝试修复它。但这并不能解决我的循环依赖问题......应用程序上下文中一些bean的依赖关系形成了一个循环:┌─────┐ | cz.moravec.Main 中定义的 sessionFactory └──────┘
@JanMoravec 你找到答案了吗?我现在面临同样的问题。
对不起,我没有解决问题。
【参考方案1】:
在初始化 SpringBoot 应用程序时是否必须将 SessionFactory 设置为 bean? 另一种解决方案是在您的 Dao 类中获取 hibernate sessionFactory / session。
以下是一个例子:
@Repository
public class CountryDao
@Autowired
private EntityManagerFactory entityManagerFactory;
private Session getSessionFactory()
return entityManagerFactory.unwrap(SessionFactory.class);
...
我可以成功获取到 Dao 类中的 SessionFactory。
但是如果你的目的是只获取当前的 Hibnerate Session 对象,下面是一种更简洁的方法:
@Repository
public class CountryDao
@Autowired
private EntityManager entityManager;
private Session getSession()
return entityManager.unwrap(Session.class);
...
我正在测试的 SpringBoot 是 2.1.3.RELEASE
【讨论】:
以上是关于Spring Boot 2.0.0 循环bean依赖EntityManger和SessionFactory的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot UnsatisfiedDependencyException 创建名称为无法解析的循环引用的 bean 时出错
当我尝试使用 Spring Boot 为 SessionFactory 创建 bean 时无法解析的循环引用
Spring Boot创建动态数据源:当前正在创建请求的bean:是否存在无法解析的循环引用?