Spring Boot 2.0.0循环bean依赖EntityManger和SessionFactory

时间:2018-04-11 18:06:06

标签: java hibernate spring-boot jpa inject

我遇到新的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>

1 个答案:

答案 0 :(得分:0)

在启动SpringBoot应用程序时是否必须将SessionFactory设置为bean? 另一种解决方案是在Dao类中获取休眠的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版本