Проблема Spring JavaConfig JPA — не определен bean-компонент с именем «entityManagerFactory»

Я нахожусь в процессе преобразования конфигурации на основе XML для веб-проекта Spring Java в JavaConfig.

Я использую JPA. Поэтому я создал дополнительный класс JavaConfig с необходимой конфигурацией. Но конфигурация JPA по какой-то причине не работает.

Вот мой [web.xml][1]

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app
@Configuration
@EnableWebMvc
//@ImportResource("contoso-jpa.xml") //Import any existing xml context files
@Import(contosoJPA.class)
//@EnableTransactionManagement //substitute for  <tx:annotation-driven/>
@ComponentScan({"com.my.contoso.webservices.rest", "com.my.contoso.services,com.my.contoso.dao"})
public class contosoConfig {

}
5.xsd"> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </context-param> <!-- Configuration locations must consist of one or more comma- or space-delimited fully-qualified @Configuration classes. Fully-qualified packages may also be specified for component-scanning --> <!-- <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.my.contoso.spring.contosoJPA</param-value> </context-param>--> <!-- Bootstrap the root application context as usual using ContextLoaderListener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Declare a Spring MVC DispatcherServlet as usual --> <servlet> <servlet-name>restservices</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext --> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </init-param> <!-- Again, config locations must consist of one or more comma- or space-delimited and fully-qualified @Configuration classes --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>com.my.contoso.spring.contosoConfig</param-value> </init-param> </servlet> <!-- This Servlet mapping means that this Servlet will handle all incoming requests --> <servlet-mapping> <servlet-name>restservices</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- for CORS --> <filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, HEAD, POST, PUT, DELETE, OPTIONS</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Content-Type, X-Requested-With, Origin, Accept</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- End for CORS --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.properties</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <filter> <filter-name>OpenEntityManagerFilter</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> <init-param> <param-name>entityManagerFactoryBeanName</param-name> <param-value>entityManagerFactory</param-value> </init-param> </filter> <filter-mapping> <filter-name>OpenEntityManagerFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/contosoDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>--> </web-app>

Вот мой основной [класс JavaConfig][2]

@Configuration
@EnableWebMvc
//@ImportResource("contoso-jpa.xml") //Import any existing xml context files
@Import(contosoJPA.class)
//@EnableTransactionManagement //substitute for  <tx:annotation-driven/>
@ComponentScan({"com.my.contoso.webservices.rest", "com.my.contoso.services,com.my.contoso.dao"})
public class contosoConfig {

}

А вот класс JavaConfig с [конфигурацией JPA][3]

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories //(basePackages = { "com.my.contoso.domain" })
public class contosoJPA {


         @Bean
        public DataSource dataSource() {
    //        return new EmbeddedDatabaseBuilder().setType(H2).build();

            DriverManagerDataSource ds = new DriverManagerDataSource();


        try {
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUsername("root");
            ds.setPassword("");
            ds.setUrl("jdbc:mysql://localhost:3306/contosodb");

        } catch (Exception e) {
    //        logger.error(e.getMessage());
            System.out.println(e);
        }
        return ds;
        }

        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
            LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
            lef.setDataSource(dataSource);
            lef.setJpaVendorAdapter(jpaVendorAdapter);
            lef.setPackagesToScan("com.my.contoso.domain");
            lef.setPersistenceUnitName("contosoPU");
            return lef;
        }

        @Bean
        public JpaVendorAdapter jpaVendorAdapter() {
            HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
            hibernateJpaVendorAdapter.setShowSql(false);
            hibernateJpaVendorAdapter.setGenerateDdl(true);
            hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
    //        hibernateJpaVendorAdapter.setDatabase(Database.H2);
            return hibernateJpaVendorAdapter;
        }

        @Bean
        public PlatformTransactionManager transactionManager() {
            return new JpaTransactionManager();
        }   

}

Полная трассировка стека:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:570)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1108)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.lookupEntityManagerFactory(OpenEntityManagerInViewFilter.java:222)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.lookupEntityManagerFactory(OpenEntityManagerInViewFilter.java:205)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:152)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:179)
    at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2430)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2419)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
    org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:570)

'entityManagerFactory' объявлен в [web.xml][1]. Ошибка говорит о том, что бин с таким именем не существует. Но я включил его в файл [JPA config][3]. Итак, я предполагаю, что bean-компоненты в файле JPA javaConfig не подхватываются. Интересно, где конфигурация не работает.


person user6123723    schedule 02.02.2014    source источник


Ответы (2)


Почему ты закомментировал

<!-- Configuration locations must consist of one or more comma- or space-delimited
       fully-qualified @Configuration classes. Fully-qualified packages may also be
       specified for component-scanning -->
<!-- <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>com.uhsarp.billrive.spring.BillriveJPA</param-value>
 </context-param>-->

?

Мне кажется, что корневой контекст должен быть загружен и сделан доступным для всего приложения через файл ContextLoaderListener. Этот context-param должен быть доступен, чтобы у корневого контекста был источник, из которого можно загружать определения bean-компонентов.

person Sotirios Delimanolis    schedule 03.02.2014
comment
Всего у меня есть 2 класса JavaConfig: основной контекст и один для JPA. Основной загружается позже в файле web.xml в объявлении сервлета. Затем основной файл конфигурации импортирует файл конфигурации JPA. Разве этого не достаточно? Я также попытался раскомментировать это и загрузить основной контекст на свое место, но не в кости. По какой-то причине файлы контекста просто не подхватываются. - person user6123723; 03.02.2014
comment
@user1324816 user1324816 Отредактируйте свой вопрос и добавьте классы/файлы контекста, которые у вас есть. Мы не хотим переходить по ссылкам. Будет легче увидеть, где чего-то не хватает. - person Sotirios Delimanolis; 03.02.2014
comment
Изменено для прямого включения исходников. Спасибо. - person user6123723; 03.02.2014
comment
@user Пожалуйста, опубликуйте также полную трассировку стека. - person Sotirios Delimanolis; 03.02.2014
comment
Добавлена ​​полная трассировка стека. Раньше я не добавлял его, так как не видел ничего выдающегося. - person user6123723; 03.02.2014
comment
@user1324816 user1324816 CORSFilter пытается загрузить bean-компонент из корневого контекста. Но необходимый компонент определяется в контексте сервлета, загружаемом DispatcherServlet. - person Sotirios Delimanolis; 03.02.2014
comment
Разве все в корневом контексте не используется во всех контекстах сервлета? - person user6123723; 03.02.2014
comment
@user Правильно, но вы загружаете не корневой контекст, а загружаете контекст сервлета с помощью DispatcherServlet. Корневой контекст загружается ContextLoaderListener. - person Sotirios Delimanolis; 03.02.2014
comment
Какой компонент вы имеете в виду, который, как вы сказали, загружается из корневого контекста? Также все мои компоненты Spring доступны в этом контексте, загруженном сервлетом. я что-то здесь упускаю - person user6123723; 03.02.2014
comment
Компоненты доступны в ApplicationContext, загруженном DispatcherServlet (он же дочерний контекст), они недоступны в ApplicationContext, загруженном ContextLoaderListener (он же ROOT-контекст). Последний пуст, содержит 0 бобов. Фильтры могут обращаться только к bean-компонентам в корневом контексте, а не из дочерних контекстов (поскольку может быть более 1 дочернего контекста, какой из них он должен выбрать!). - person M. Deinum; 03.02.2014
comment
@user1324816 user1324816 Как сказал М. Дейнум выше, DispatcherServlet загружает дочерний контекст (контекст сервлета), который доступен только ему самому. CORSFilter пытается найти bean-компоненты в корневом контексте, но у вас его нет, потому что у вашего ContextLoaderListener нет contextConfigLocation. - person Sotirios Delimanolis; 03.02.2014

я бы попытался удалить параметры и вызвать методы bean вручную:

@Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(dataSource());
        lef.setJpaVendorAdapter(jpaVendorAdapter());
        lef.setPackagesToScan("com.my.contoso.domain");
        lef.setPersistenceUnitName("contosoPU");
        return lef;
    }

затем попробуйте выполнить отладку/отладку, если Spring доберется до любого метода из этого класса конфигурации.

Может быть, смешивание конфигурации web.xml с конфигурацией java - не лучшая идея? Вы не думали о переносе? :)

person freakman    schedule 03.02.2014
comment
Не могли бы вы уточнить, что вы имеете в виду, вызывая методы компонента вручную? Спасибо. Также вы можете помочь мне понять часть миграции из web.xml, чтобы конкурировать с javaconfig? Мне трудно найти документацию по переходу на JavaConfig. Спасибо еще раз! - person user6123723; 03.02.2014
comment
эти 2 строки - lef.setDataSource(dataSource()); lef.setJpaVendorAdapter(jpaVendorAdapter()); вы вызываете здесь методы Bean вручную, честно говоря, я никогда не использовал параметры, которые автоматически связывают bean-компоненты из одного и того же класса конфигурации (возможно, они работают одинаково). Насчет конфига java - завтра приведу пример, сейчас нет времени его искать. Вы пытались поставить какой-нибудь Syste.out.println, чтобы проверить, вызывается ли ваш класс конфигурации? - person freakman; 03.02.2014