Переход с spring boot 1.3.8.RELEASE на 1.5.2.RELEASE — Neo4jDataAutoConfiguration переопределяет sessionFactory по умолчанию

У меня было рабочее приложение для весенней загрузки, и я пытаюсь перейти с Spring boot 1.3.8.RELEASE на 1.5.2.RELEASE. В моем рабочем треке 1.3.8.RELEASE я уже использовал hibernate 5, т.е. у меня была следующая зависимость в y pom

     <dependency> 
         <groupId>org.hibernate</groupId> 
         <artifactId>hibernate-java8</artifactId> 
         <version>${hibernate.version}</version> 
     </dependency> 

с Spring boot 1.5 это не требуется, поэтому я изменил это на зависимость по умолчанию от hibernate 5, то есть hibernate-core, и удалил объявление версии.

<dependency>
     <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
</dependency>

Однако я не могу понять, почему мой тест говорит:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]

Я определенно настроил фабрику сеансов

@Profile("Development")
@Configuration
@EnableTransactionManagement
@Order(value=1)
public class PersistenceConfigDevelopment {

    @Bean
    public org.apache.commons.dbcp.BasicDataSource dataSourceReadWrite() {

        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://localhost:5432/testDB");
        dataSource.setUsername("admin");
        dataSource.setPassword("veryBigSecret!");
        dataSource.setInitialSize(20);
        dataSource.setMaxActive(-1);

        return dataSource;
    }


    @Bean
    public org.springframework.orm.hibernate5.LocalSessionFactoryBean sessionFactory() {

        org.springframework.orm.hibernate5.LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(this.dataSourceReadWrite());
        sessionFactory.setPackagesToScan("org.testApp");
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }


       @Bean
       public  org.springframework.orm.hibernate5.HibernateTransactionManager  transactionManager() {
          HibernateTransactionManager txManager = new HibernateTransactionManager();
          txManager.setSessionFactory(sessionFactory().getObject());
          return txManager;
       }


       @Bean
       public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
          return new PersistenceExceptionTranslationPostProcessor();
       }



    @Bean
    public  Properties hibernateProperties() {

    return new Properties() {

        {
                setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
                setProperty("hibernate.chach.provider_class", "org.hibernate.cache.NoCacheProvider");
                setProperty("hibernate.show_sql", "true");              
                setProperty("hibernate.hbm2ddl.auto", "create-drop");

                setProperty("hibernate.cache.use_second_level_cache", "false");
                setProperty("hibernate.cache.use_query_cache", "false");

                //isolation level
                setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_SERIALIZABLE));

             }
          };
       }

}

вот как я начинаю свой весенний тест загрузки 1.5.2:

@RunWith(SpringRunner.class)
@TestExecutionListeners(listeners={ 
                                    DependencyInjectionTestExecutionListener.class,
                                    DirtiesContextTestExecutionListener.class,
                                    WithSecurityContextTestExecutionListener.class 
                                    }
        )
@SpringBootTest(
        classes = {
        SecurityWebApplicationInitializerDevelopment.class, 
        SecurityConfigDevelopment.class, 
        TomcatEmbededDevelopmentProfile.class, 
        Internationalization.class, 
        MVCConfigDevelopment.class,
        PersistenceConfigDevelopment.class,
        } 

    )
@WebAppConfiguration
@ActiveProfiles(TestAppConfigurationProfiles.DEVELOPMENT_PROFILE)
@WithMockUser(username="alice",roles={"USER","ADMIN"} )
public class mainTests { 
     ......

по какой-то причине Spring boot 1.5 не находит мою фабрику сеансов. Но почему? Я использую неправильную зависимость? Я настроил фабрику сеансов Hibernate5 и диспетчер транзакций как компонент.

Вот часть моей помпы:

    <?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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>

    </parent>


    <groupId>test</groupId>
    <artifactId>testApp</artifactId>
    <name>testApp</name>
    <version>1.0-SNAPSHOT</version>


    <properties>

        <hibernate.version>5.2.9.Final</hibernate.version>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version>
        <maven-source-plugin.version>3.0.1</maven-source-plugin.version>
        <maven-javadoc-plugin.version>2.10.4</maven-javadoc-plugin.version>
        <maven-install-plugin.version>2.5.2</maven-install-plugin.version>
        <maven-assembly-plugin.version>3.0.0</maven-assembly-plugin.version>

        <java.version>1.8</java.version>

        <start-class>org.testApp.core.Application</start-class>

    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <exclusions> 
                <exclusion> 
                    <groupId>org.apache.tomcat</groupId> 
                    <artifactId>tomcat-jdbc</artifactId> 
                </exclusion> 
            </exclusions>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
        </dependency>

        <!-- Thymeleaf -->    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>nz.net.ultraq.thymeleaf</groupId>
            <artifactId>thymeleaf-layout-dialect</artifactId>
        </dependency>

        <!-- Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
        </dependency>

        <!-- Hibernate -->


        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

        <!-- Apache -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
        </dependency>



        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

      <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>  
      </dependency>
      <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.3</version>
      </dependency>


      <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-neo4j</artifactId>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-gemfire</artifactId>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp2</artifactId>
      </dependency>
    </dependencies>   

</project>

вот как я запускаю свое приложение

@ComponentScan({"org.testApp.*"})
@Configuration
@EnableAutoConfiguration
@EnableWebSocket
@SpringBootApplication
public class Application extends SpringBootServletInitializer  {
...

Дополнение 29 марта 2017 г.

Проанализировав конфигурацию запуска, я нашел строку:

2017-03-29 10:45:01.084  INFO 11022 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'sessionFactory' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=persistenceConfigDevelopment; factoryMethodName=sessionFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/testApp/config/persistence/PersistenceConfigDevelopment.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration; factoryMethodName=sessionFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.class]]

Чего я не понимаю, так это почему Neo4jDataAutoConfiguration.class переопределяет мой пользовательский bean-компонент persistenceConfigDevelopment.

Более того, если я удалю @EnableAutoConfiguration и @SpringBootApplication в своем основном классе Application, тогда приложение запустится и правильная фабрика сеансов будет успешно создана, но затем произойдет сбой, поскольку он не может найти bean-компонент InternalResourceViewResolver, но это ожидается, поскольку обычно @EnableAutoConfiguration заботится о эти бобы.

`Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type` 'org.springframework.web.servlet.view.InternalResourceViewResolver' available

person Tito    schedule 27.03.2017    source источник
comment
Поддержка автоматической настройки Neo4J добавляет bean-компонент с именем sessionFactory, переопределяющий настроенный bean-компонент.   -  person M. Deinum    schedule 30.03.2017
comment
@М. Deinum хорошо, почему он добавляет его, если я явно настроил его в своей конфигурации, то есть в соответствии с классом PersistenceConfigDevelopment выше. Это не имеет для меня никакого смысла. Поведение по умолчанию должно заключаться в том, что если пользователь настроил фабрику сеансов, то есть спящий режим, то Neo4J ничего не должен делать.   -  person Tito    schedule 30.03.2017
comment
Я думаю, что это будет проблемой для многих пользователей Spring, поскольку Spring не должен переопределять bean-компоненты, настроенные вручную.   -  person Tito    schedule 30.03.2017
comment
Переопределение связано с конфликтами имен. Может быть только один bean-компонент с именем sessionFactory (я не проверял автоконфигурацию neo4j, но подозреваю, что она создает bean-компонент ne04j с именем sessionFactory). И какой из них победит, зависит от порядка загрузки классов конфигурации.   -  person M. Deinum    schedule 30.03.2017
comment
Насколько я знаю, весной невозможно сказать, какие bean-компоненты загружаются первыми, по крайней мере, для каждой аннотации, которая может указать Neo4j для загрузки вторым. Но это не меняет того факта, что бизнес-логика автоматической настройки Neo4j должна быть достаточно интеллектуальной, чтобы проверить, настроил ли пользователь @bean с именем sessionFactory, тогда Neo4j не должен создавать свой собственный bean-компонент с тем же именем и должен вернуться выключенный.   -  person Tito    schedule 30.03.2017
comment
Он проверяет только по типу, а не по имени. Но если вам не нужен neo4j, то не добавляйте его (или отключите автоматическую настройку). Вы можете заказать классы конфигурации и загрузить их в определенном порядке (ваши загружаются первыми перед другими и, следовательно, переопределяются другими настроенными bean-компонентами). Механизм переопределения применяется ко всем bean-компонентам (и вы можете отключить его на уровне ApplicationContext, чтобы создать исключение вместо переопределения bean-компонентов).   -  person M. Deinum    schedule 30.03.2017
comment
это кажется мне запросом функции   -  person Tito    schedule 30.03.2017
comment
ну, у меня была установлена ​​​​аннотация @Order (value = 1), но я все равно получил ошибку, поэтому Order не помог.   -  person Tito    schedule 30.03.2017
comment
Если вы хотите, чтобы он изменился, зарегистрируйте запрос в GitHub для весенней загрузки.   -  person M. Deinum    schedule 30.03.2017
comment
М. Дейнум, спасибо за ваше время, я сделаю это, так как считаю, что это имеет смысл.   -  person Tito    schedule 30.03.2017


Ответы (1)


Я нашел решение своей проблемы, т.е.

удалили из pom все, что ссылается на neo4j, т.е.

  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
  </dependency>

затем добавьте в основной класс приложения следующие исключения:

@SpringBootApplication(exclude = JpaRepositoriesAutoConfiguration.class)
public class Application extends SpringBootServletInitializer  {

Я еще не знаю, где именно ошибка, но я точно знаю, что когда я удаляю spring-data-neo4j, все работает хорошо, и все мои тесты проходят.

person Tito    schedule 30.03.2017