2013-10-24 2 views
2

Это Транзактная аннотаций находится в DAO слое он работает, если я переместить его на сервисный уровень, я получаю исключение:Spring: Не удается переместить @Transactioanl аннотацию от DAO к слою Service

Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.RestAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch 

Здесь мой код:

CatalogDAOInterface:

public interface CatalogDAOInterface { 

    public List<Product> getAllProduct(); 

    public List<Category> getAllCategories() ; 

    public List<Media> getAllMedias(); 

} 

CatalogDAO:

@Repository 
@SuppressWarnings({"unchecked", "rawtypes"}) 
public class CatalogDAO implements CatalogDAOInterface { 

    @Autowired private SessionFactory sessionFactory; 


    @Override 
    public List<Product> getAllProduct() { 
      Session session = sessionFactory.getCurrentSession(); 
      List products = session.createQuery("from Product").list(); 
      return products; 
    } 

    @Override 
    public List<Category> getAllCategories() { 
      Session session = sessionFactory.getCurrentSession(); 
      List products = session.createQuery("from Category").list(); 
      return products; 
    } 

    @Override 
    public List<Media> getAllMedias() { 
      Session session = sessionFactory.getCurrentSession(); 
      List medias = session.createQuery("from Media").list(); 
      return medias; 
    } 

} 

CatalogServiceInterface:

public interface CatalogServiceInterface { 

    public List<Category> getAllCategories(); 
    public List<Product> getAllProducts(); 
    public List<Media> getAllMedias(); 

} 

CatalogService:

@Service 
public class CatalogService implements CatalogServiceInterface{ 

    @Autowired 
    private CatalogDAO catalogDAO; 

     @Transactinal 
    @Override 
    public List<Product> getAllProducts() { 
     return catalogDAO.getAllProduct(); 
    } 

     @Transactinal 
    @Override 
    public List<Category> getAllCategories() { 
     return catalogDAO.getAllCategories(); 
    } 

     @Transactinal 
    @Override 
    public List<Media> getAllMedias() { 
     return catalogDAO.getAllMedias(); 
    } 

} 

сервлет-context.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:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> 

    <!-- Enable @Controller annotation support --> 
    <mvc:annotation-driven /> 

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
     up static resources in the ${webappRoot}/resources directory --> 
    <mvc:resources mapping="/resources/**" location="/resources/" /> 

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
     in the /WEB-INF/views directory --> 
    <bean 
     class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <property name="prefix" value="/WEB-INF/views/" /> 
     <property name="suffix" value=".jsp" /> 
    </bean> 

    <context:component-scan base-package="com.adam.czibere" /> 

<!-- <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" --> 
<!--  destroy-method="close"> --> 
<!--  <property name="driverClassName" value="com.mysql.jdbc.Driver" /> --> 
<!--  <property name="url" value="jdbc:mysql://localhost:3306/pizzashop" /> --> 
<!--  <property name="username" value="root" /> --> 
<!--  <property name="password" value="czadam" /> --> 
<!--  <property name="validationQuery" value="SELECT 1" /> --> 
<!-- </bean> --> 

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close"> 
     <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" /> 
     <property name="url" value="jdbc:jtds:sqlserver://something" /> 
     <property name="username" value="something" /> 
     <property name="password" value="something" /> 
     <property name="validationQuery" value="SELECT 1" /> 
    </bean> 

    <!-- Hibernate Session Factory --> 
    <bean id="mySessionFactory" 
     class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
     <property name="dataSource" ref="myDataSource" /> 
     <property name="packagesToScan"> 
      <array> 
       <value>com.adam.czibere</value> 
      </array> 
     </property> 
     <property name="hibernateProperties"> 
      <value> 
       hibernate.dialect=org.hibernate.dialect.MySQLDialect 
      </value> 
     </property> 
    </bean> 

    <!-- Hibernate Transaction Manager --> 
    <bean id="transactionManager" 
     class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="mySessionFactory" /> 
    </bean> 

    <!-- Activates annotation based transaction management --> 
    <tx:annotation-driven transaction-manager="transactionManager" /> 

</beans> 

Трассировка стека:

exception 

javax.servlet.ServletException: Servlet.init() for servlet appServlet threw exception 
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) 
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) 
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    java.lang.Thread.run(Thread.java:724) 


root cause 

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'catalogAPIController' defined in file [C:\Users\czadam\Documents\workspace 2.0\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\SalesWizard\WEB-INF\classes\com\adam\czibere\CatalogAPIController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.CatalogAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch 
    org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:288) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) 
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) 
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) 
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) 
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) 
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) 
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) 
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645) 
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508) 
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449) 
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133) 
    javax.servlet.GenericServlet.init(GenericServlet.java:160) 
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) 
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) 
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    java.lang.Thread.run(Thread.java:724) 


root cause 

org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.CatalogAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch 
    org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:158) 
    org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:110) 
    org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) 
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) 
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) 
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) 
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) 
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) 
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) 
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645) 
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508) 
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449) 
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133) 
    javax.servlet.GenericServlet.init(GenericServlet.java:160) 
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) 
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) 
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    java.lang.Thread.run(Thread.java:724) 


root cause 

java.lang.IllegalArgumentException: argument type mismatch 
    sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    java.lang.reflect.Constructor.newInstance(Constructor.java:526) 
    org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147) 
    org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:110) 
    org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) 
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) 
    org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) 
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) 
    org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) 
    org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) 
    org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) 
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) 
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588) 
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645) 
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508) 
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449) 
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133) 
    javax.servlet.GenericServlet.init(GenericServlet.java:160) 
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) 
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936) 
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) 
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) 
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    java.lang.Thread.run(Thread.java:724) 

Часть моего контроллера:

@Controller 
@RequestMapping(value = "api", produces = "application/json") 
public class CatalogAPIController { 

    CatalogService catalogService; 

    private static final int BUFFER_SIZE = 4096; 

    @Autowired 
    public CatalogAPIController(CatalogService catalogService) { 
     this.catalogService = catalogService; 
    } 

    // get all categories 
    @RequestMapping(value = "category/all", produces = "application/json;charset=UTF-8") 
    @ResponseBody 
    public String getAllCategories() { 
     JSONArray categoryArray = new JSONArray(); 
     for (Category cat : catalogService.getAllCategories()) { 
      JSONObject categoryJSON = new JSONObject(); 
      try { 
       categoryJSON.put("id", cat.getId()); 
       categoryJSON.put("name", cat.getName()); 

       categoryJSON.put("imageMediaID", cat.getImageMediaID()); 
       categoryJSON.put("parentID", cat.getParent().getId()); 

       // Media 
       JSONArray mediaArray = new JSONArray(); 
       for (Media item : cat.getMedias()) { 
        if (item != null) { 

         mediaArray.put(item.getId()); 
        } 
       } 
       categoryJSON.put("mediaIDs", mediaArray); 

       categoryJSON.put("modifiedDate", cat.getModifiedDate()); 

       categoryArray.put(categoryJSON); 
      } catch (JSONException e) { 

       e.printStackTrace(); 
       return "Error: " + e.getMessage(); 
      } 

     } 
     return categoryArray.toString(); 
    } 

} 
+0

Пожалуйста, пост полный стек исключений трассировки и ваш класс 'RestAPIController'. –

+0

Когда вы добавляете аннотации '@ Transactional' к вашему классу обслуживания, Spring добавит прокси в ваш' RestAPIController', а не экземпляр реального сервиса. Это может вызвать «IllegalArgumentException», но, как говорит Sotirios, следует разместить как стек, так и код контроллера, чтобы мы могли получить немного больше информации. –

+0

Я отправил трассировку стека и контроллер. – czadam

ответ

0

две вещи привлекли мое внимание

1.

@Transactinal 

это опечатка или вы импортировать другой аннотацию, он должен быть @Transactional

2.

почему вы не используете интерфейс, если вы уже их определения?

вместо

@Autowired 
public CatalogAPIController(CatalogService catalogService) { 
    this.catalogService = catalogService; 
} 

изменить его на

@Autowired 
public CatalogAPIController(CatalogServiceInterface catalogService) { 
    this.catalogService = catalogService; 
} 

То же самое относится к интерфейсу DAO.

Я не понимаю отношения между перемещением транзакций из одного места в другое. Посмотрите, поможет ли это

0

Это то, что я могу представить с подробностями, которые вы предоставили. Я считаю, что у вас нет библиотек CGLIB в вашем пути к классам. Таким образом, для Spring для применения поведения @Transactional он проксирует ваш аннотированный класс с проксими JDK. Прокси-серверы JDK используют интерфейсы, они не могут проксировать базовые классы. Таким образом, прямой суперкласс прокси-сервера - java.lang.reflect.Proxy.

В этом случае ваш бобин CatalogService будет обернут в прокси-сервер, класс которого примерно Proxy$1. Когда Spring пытается создать экземпляр @Controller класса, CatalogAPIController, посредством отражения с помощью конструктора

@Autowired 
public CatalogAPIController(CatalogService catalogService) { 
    this.catalogService = catalogService; 
} 

он потерпит неудачу, потому что аргумент, передаваемый методу Constructor#newInstance(Object...) не будет соответствовать типу параметра CatalogService, поскольку Proxy$1 не подтип CatalogService ,

Причина, по которой это не произошло, когда вы делали аннотацию DAO, я считаю, что ваш класс DAO не находится в пакете component-scan, который применял поведение @Transactional. Так могло показаться, что работает @Transactional, но это не так. Поскольку @Transactional не работал, не прокси не был создан, и поэтому весна не жаловался инъекционного это поле

@Autowired 
private CatalogDAO catalogDAO; 

в своем классе обслуживания.

Одним из возможных решений является то, что Луис рекомендовал и изменил ваши типы параметров на интерфейс в качестве прокси-серверов JDK для реализации интерфейсов, т.е. интерфейсы являются супертипами экземпляра класса Proxy$1, сгенерированного для переноса вашего компонента.

Другим решением является предоставление банок CGLIB на вашем пути к классу. Весна будет их обнаруживать и использовать. Затем он сможет проксировать ваш класс базовым классом, а не интерфейсом. You can find the libraries here.

Не забудьте сообщить Spring проксировать целевой класс с

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> 
5

Когда весна применением @Transactional аннотации внутри, он создает прокси-класс, который оборачивает свой класс обслуживания.

Итак, когда ваш сервисный компонент создан в контексте вашего приложения, вы получаете объект, который не имеет тип CatalogService, но некоторый класс Proxy$1.

Этот класс Proxy$1 не распространяется CatalogService, но он будет реализовывать CatalogServiceInterface. Поэтому, когда создается ваш bean-компонент CatalogAPIController, он пытается вызвать его конструктор с вашим объектом Proxy$1, который является неправильным типом, поскольку ваш конструктор ожидает класс.

Итак, если вы хотите изменить свой контроллер, чтобы использовать интерфейс вместо реализации, то я считаю, что ваши проблемы исчезнут. Это связано с тем, что Proxy$1 ИСПОЛЬЗУЮТ CatalogServiceInterface.

Мораль рассказа: Всегда использовать интерфейс, если вы ссылаетесь вашей разметке (если вы решите предоставить другую реализацию (например CatalogService2, который также реализует CatalogServiceInterface, вы можете подключить только, что в вашем CatalogAPIController, если его конструктор используя интерфейс, а не класс (и, по сути, это то, что происходит, когда вы указываете @Transactional.

Надежда, что имеет смысл.