web-dev-qa-db-ja.com

Springデータリポジトリの自動配線が失敗する

私はかなり長い間この問題に取り組んでいて、それを機能させることができません。あなたの何人かが私を助けるためにあなたの時間を割くことができることを願っています。

シナリオ
SpringMVCを使用するWebアプリケーションを構築しています。このWebアプリは、永続層を含む別のMavenプロジェクトを使用することは想定されていません。永続層は現在、サービスとSpringDataリポジトリのみで構成されています。永続層自体は、ローカルのMySQLインスタンスに対して機能します。

私の問題
永続層のJUnitテストがあります。テストはエンティティをロードして保存します。これはサービスを介して処理されます。どちらの操作も正常に機能します。

今、私はwebappのMavenプロジェクト内のJUnitテスト内で同じことを試みています。もう一度、エンティティを保存してロードしようとしています。しかし、今回は失敗します。 Springは、サービス内のリポジトリ参照を自動配線できなかったと述べています。これは、適合するBeanがないためです。

私はこれを解決するために複数のアプローチを試みました。たとえば、直接配線を使用したり、修飾子を指定したりします。私のアプローチはどれもうまくいきませんでした。シナリオを単純化した2つの完全な新しいMavenプロジェクトを構築しましたが、必要な要素は同じままにしました。そこではそれは魅力のように機能しました。作業例の設定を変更したので、これで何が間違っているのかわかりません。


永続性プロジェクトからのファイル

persistence.xml

 <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
          http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-autowire="byName">

    <tx:annotation-driven transaction-manager="transactionManager" />
    <context:annotation-config />

    <context:component-scan base-package="com.company.dev.webapp" />
    <jpa:repositories base-package="com.company.dev.webapp.repository" query-lookup-strategy="create-if-not-found" />

    <bean id="exceptionPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <!-- Data Source -->
    <bean id="dataSource" class="org.Apache.commons.dbcp.BasicDataSource" destroy-method="close" >
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost/webapp" />
        <property name="username" value="root" />
        <property name="password" value="" />
        <property name="initialSize" value="20" />
    </bean>

    <!-- Hibernate -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="webapp-persistence" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="database" value="MYSQL" />
            </bean>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
</beans>



QuestionService

@NoRepositoryBean
public interface QuestionService extends QuestionRepository {
   Question findById(Long id);

   Question findByUniqueRef(String uniqueRef);

   List<Question> findAll(Sort sort, Page page);

   List<Question> findAll(Page page);
}



QuestionServiceImpl

@Transactional
@Service
public class QuestionServiceImpl implements QuestionService {

    @Autowired
    QuestionRepository questionRepository;

    @Override
    public Question save(Question entity) {
        return questionRepository.save(entity);
    }
    [Some methods ommited]
}



QuestionRepository

@Transactional
@Repository
public interface QuestionRepository extends JpaRepository<Question, Long>{

}


webappプロジェクトからのファイル

web.xml

<?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_2_5.xsd">

  <!-- Spring Bind Macro -->
    <context-param> 
        <param-name>defaultHtmlEscape</param-name> 
        <param-value>true</param-value> 
    </context-param> 

  <!-- Log4J -->
    <context-param> 
        <param-name>log4jConfigLocation</param-name> 
        <param-value>/WEB-INF/log4j.xml</param-value> 
    </context-param> 
    <context-param> 
        <param-name>log4jRefreshInterval</param-name> 
        <param-value>15000</param-value> <!-- intervall in millisekunden!!! --> 
    </context-param> 
    <context-param> 
        <description>Zur Konfiguration von Log4j</description> 
        <param-name>webAppRootKey</param-name> 
    <!-- Diesen Wert bei jeder Anwendung anpassen! -->
        <param-value>app.root</param-value> 
    </context-param> 

    <!-- Application Context -->    
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:persistence-context.xml
            /WEB-INF/spring/app-config.xml
        </param-value>
    </context-param>


  <!-- Reads request input using UTF-8 encoding -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

  <!-- Enables clean URLs with JSP views e.g. /welcome instead of /app/welcome -->
    <filter>
        <filter-name>UrlRewriteFilter</filter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>UrlRewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

  <!-- Log4j Konfiguration laden-->
    <listener> 
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
    </listener>

  <!-- Handles all requests into the application -->
    <servlet>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/mvc-config.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>oemInViewFilter</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>oemInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

app-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">

  <!-- Application Message Bundle -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/messages/messages"/>
        <property name="cacheSeconds" value="0"/>
    </bean>

  <!-- Services and Repositories -->
    <bean class="com.company.dev.webapp.impl.SimpleQuestionRepository" id="questionRepository">
    <!-- ... -->
    </bean>

  <!-- Events -->
    <bean class="com.company.dev.webapp.event.impl.ApplicationContextEventGateway" id="eventGateway"/>

  <!-- Search and indexing -->
    <import resource="search-indexing.xml"/>

</beans>

mvc-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">

  <!-- Application Message Bundle -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/messages/messages"/>
        <property name="cacheSeconds" value="0"/>
    </bean>

  <!-- Services and Repositories -->
    <bean class="com.company.dev.webapp.impl.SimpleQuestionRepository" id="questionRepository">
    <!-- ... -->
    </bean>

  <!-- Events -->
    <bean class="com.company.dev.webapp.event.impl.ApplicationContextEventGateway" id="eventGateway"/>    
</beans>

JUnitテスト

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration
@ContextConfiguration({"classpath:persistence-context.xml", "classpath:app-config.xml"})
@Transactional
public class QuestionServiceTest {

    @Autowired
    private QuestionService questServ;
    private Question quest;

    @Before
    public void setUp() throws Exception {
        if (quest == null) {
            quest = new Question();
            quest.setQuestion("Why?!");
            quest.setText("Please help!");
            quest.setCreationDate(new Date(System.currentTimeMillis()));
            questServ.save(quest);
        }
    }

    @Test
    public void loadQuestion() {
        Question check = questServ.findOne(quest.getId());
        Assert.assertNotNull(check);
        Assert.assertEquals(check, quest);
    }
}


例外

08:28:59 ERROR [test.context.TestContextManager]: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@15a3a1] to prepare test instance [com.company.dev.webapp.service.QuestionServiceTest@a9a32c]
Java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.Java:308)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.Java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.Java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.Java:333)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.Java:220)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.Java:301)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.Java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.Java:303)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.Java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:184)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.Java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.Java:61)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.Java:31)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.Java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.Java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.Java:180)
    at junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.Java:39)
    at org.Apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.Java:518)
    at org.Apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.Java:1052)
    at org.Apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.Java:906)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'answerController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.company.dev.webapp.service.QuestionService com.company.dev.webapp.web.AnswerController.questionRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'questionServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.dev.webapp.repository.QuestionRepository com.company.dev.webapp.service.impl.QuestionServiceImpl.questionRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.dev.webapp.repository.QuestionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:286)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.Java:1064)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.Java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.Java:574)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.Java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:425)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.Java:84)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.Java:1)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.Java:280)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.Java:304)
    ... 24 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.company.dev.webapp.service.QuestionService com.company.dev.webapp.web.AnswerController.questionRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'questionServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.dev.webapp.repository.QuestionRepository com.company.dev.webapp.service.impl.QuestionServiceImpl.questionRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.dev.webapp.repository.QuestionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:507)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:283)
    ... 38 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'questionServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.dev.webapp.repository.QuestionRepository com.company.dev.webapp.service.impl.QuestionServiceImpl.questionRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.dev.webapp.repository.QuestionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:286)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.Java:1064)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.Java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.Java:838)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.Java:780)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.Java:697)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:478)
    ... 40 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.dev.webapp.repository.QuestionRepository com.company.dev.webapp.service.impl.QuestionServiceImpl.questionRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.dev.webapp.repository.QuestionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:507)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:84)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:283)
    ... 51 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.dev.webapp.repository.QuestionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.Java:914)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.Java:783)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.Java:697)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:478)
    ... 53 more



これはコード全体です。他に何か必要なことがあれば、今すぐさせてください。私はこれを解決する方法が本当にわからないので、このトピックに関する助けに感謝します。

宜しくお願いします

12
Makenshi

私は解決策を見つけました。 QuestionRepositoryのカスタム実装を作成し、それをxmlを介して直接配線した後、謎を解決する新しい例外が表示されました。 Bean宣言

<!-- Services and Repositories -->
    <bean class="com.company.dev.company.impl.SimpleQuestionRepository" id="questionRepository">
    <!-- ... -->
    </bean>

メモリ内のコレクション内のオブジェクトのみを永続化する単純な自己記述リポジトリのBeanを提供することを目的としていました。

IDがquestionRepositoryであるため、SpringはクラスquestionRepositoryQuestionServiceImplフィールドに名前を付けて自動配線を試みます。

長い話、短い事実:他の誰かがあなたの設定ファイルで定義したかもしれない名前を再確認してください。 :)

4
Makenshi