2012-03-22 8 views
7

DAOをテストしましたが、動作しませんでした。次のエラーが発生します。@Transactionalの使用中にautowired依存関係の注入が失敗しました

Tests in error: 
    testAccountOperations(com.tsekhan.rssreader.dao.HibernateControllerTest): Error creating bean with name 'com.tsekhan.rssreader.dao.HibernateControllerTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.tsekhan.rssreader.dao.HibernateController com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController; nested exception is java.lang.IllegalArgumentException: Can not set com.tsekhan.rssreader.dao.HibernateController field com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController to $Proxy25 

マイDAO:

@Service 
@Scope("singleton") 
public class HibernateController extends HibernateDaoSupport { 

    @Autowired 
    public SessionFactory sessionFactory; 

    @Transactional 
    public void addAcount(Account account) { 
     sessionFactory.getCurrentSession().saveOrUpdate(account); 
    } 
} 

このDAOのための私のテスト:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:/applicationContext.xml") 
public class HibernateControllerTest { 

    @Autowired 
    HibernateController hibernateController; 

    private Set<Channel> getTestChannelList(String channelLink) { 
     Channel testChannel = new Channel(); 
     testChannel.setSourceLink(channelLink); 
     Set<Channel> testChannelList = new HashSet<Channel>(); 
     testChannelList.add(testChannel); 
     return testChannelList; 
    } 

    private Account getTestAccount(String accountLogin, String channelLink) { 
     Account testAccount = new Account(); 
     testAccount.setAccountLogin(accountLogin); 
     testAccount.setChannelList(getTestChannelList(channelLink)); 
     return testAccount; 
    } 

    @Test 
    public void testAccountOperations() { 
     hibernateController 
       .addAcount(getTestAccount("test_login", "test_link")); 
    } 
} 

マイapplicationContext.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" 
    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.1.xsd 
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.1.xsd" 
     default-autowire="byName"> 

    <!-- Enabling spring-transaction annotations --> 
    <tx:annotation-driven transaction-manager="transactionManager"/> 

    <!-- Enabling annotation-driven configurating --> 
    <context:annotation-config /> 

    <!-- Creation of transaction manager --> 

    <bean id="transactionManager" scope="singleton" 
     class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory"/> 
    </bean> 

    <bean id="sessionFactory" scope="singleton" 
     class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
     <property name="configLocation" value="classpath:/hibernate.cfg.xml"/> 
     <property name="configurationClass"> 
      <value>org.hibernate.cfg.AnnotationConfiguration</value> 
     </property> 
    </bean> 
    <!-- 
    A Spring interceptor that takes care of Hibernate session lifecycle. 
    --> 
    <bean id="hibernateInterceptor" 
      class="org.springframework.orm.hibernate3.HibernateInterceptor"> 
     <property name="sessionFactory"> 
      <ref bean="sessionFactory"/> 
     </property> 
    </bean> 

    <bean name="employeeDAO" scope="prototype" 
     class="com.tsekhan.rssreader.dao.HibernateController" /> 

    <!-- Searching for hibernate POJO files in package com.tsekhan.rssreader.web --> 
    <context:component-scan base-package="com.tsekhan.rssreader.web" /> 
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> 
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 

</beans> 

DAOで@Transactionalにコメントすると、Beanが正しく作成されることに注意してください。何が起こるのですか?

+0

私はDAOクラスのために、 '@ Service'の代わりに' @ Repository'アノテーションを使うのが良いです。 –

答えて

22

まず最初にコントローラの名前がDAOに終わってしまうのは本当に悪いです。コントローラとDAOはすべて異なる目的を持っています。

サービスまたはDAOクラスに@Transactionalを追加すると、トランザクションで機能するようにするには、そのクラスのプロキシを作成する必要があります。プロキシクラス(クラスを考慮するクラスこれはプロキシされている)メソッドのバネはトランザクションを開始し、例外がトランザクションを完了することがない場合に実行後に、これはAOPとアノテーションを介して春に実行されます。コードで説明する。

public class OriginalDaoImpl implements OriginalDao extends DaoSupport { 

    public void save(Object o){ 
     manager.save(o); 
    } 
} 

public class ProxyDaoImpl implements OriginalDao { 

    private OriginalDao originalDaoImpl; //instance of OriginalDaoImpl 
    public void save(Object o){ 
     try{ 
      transaction.start(); 
      originalDaoImpl.save(o); 
      transaction.commit(); 
     }catch(Exception e){ 
      transaction.rollback(); 
     }finally{ 
      //clean up code 
     } 
    } 
} 

これは正確な実装ではなく、基礎コードであることがわかります。トランザクションがどのようにあなたのために機能するかをご覧ください。キーポイントは、OriginalDaoImplとProxyDaoImplの両方が同じインターフェースを実装するので、このインジェクションを簡単にするinterface OriginalDaoです。それゆえ、それらは入れ替えることができ、すなわちプロキシは元のものとなる。この動的プロキシは、Java動的プロキシによってJavaで作成できます。さて、あなたのクラスがインターフェースを実装していない場合、置き換えが起こるのはもっと難しくなります。 私が知る限り、CGLIBのライブラリの1つは、このようなシナリオでは、クラスの動的サブクラスを考慮し、オーバーライドされたメソッドで上記のように魔法を実行します。super.save(o)を呼び出して元のコードに委譲します。

今は注射の問題です。

  1. インターフェイスを作成してDAOを実装するようにしてください。春にはJDKプロキシがデフォルトとして動作します。
  2. 限り、例外はそれが型「HibernateController」であるように注入された豆を期待していますが、そのされていないとして、それが投げている懸念している<tx:annotation-driven transaction-manager="transactionManager"/>

proxy-target-class="true"属性を追加します。

参考までに、以下のリンクを参照してください。

  1. 10.5.6 Using @Transactional
  2. Spring AOP Doc

この情報がお役に立てば幸いです!!!!!。

+2

インタフェースを注入するときに 'proxy-target-class =" true "'は必要ないかもしれないことを明らかにするべきでしょう。また、 'proxy-target-class =" true "'はインタフェース上で '@ Transactional'を破ります。それ以外に+1。 – alexkasko

+0

@ alx3appsええ、私の心をクリックしてくれなかったよ。 –

+0

偉大な答えと良い説明 – cowls

0

Spring MVCを使用している場合は、servlet context fileで特定のコントローラクラスだけをスキャンしてください。それ以外の場合は、2回スキャンされ、トランザクションはアプリケーションコンテキストで使用できません。

関連する問題