2

它的事务注释在它工作的 DAO 层中,如果我将它移动到服务层,我会得到异常:

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

这是我的代码:

目录DAO接口:

public interface CatalogDAOInterface {

    public List<Product> getAllProduct();

    public List<Category> getAllCategories() ;

    public List<Media> getAllMedias();

}

目录DAO:

@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;
     }   

}

目录服务接口:

public interface CatalogServiceInterface {

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

}

目录服务:

@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();
    }

}

servlet-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();
    }

}
4

3 回答 3

6

当 Spring 在@Transactional内部应用注解时,它会创建一个代理类来包装您的服务类。

因此,当在应用程序上下文中创建服务 bean 时,您将获得一个不是类型CatalogService而是某个Proxy$1类的对象。

这个Proxy$1类不会扩展CatalogService,但会实现CatalogServiceInterface。因此,当您的CatalogAPIControllerbean 被创建时,它会尝试使用Proxy$1错误类型的对象调用其构造函数,因为您的构造函数需要一个类。

因此,如果您要更改控制器以使用接口而不是实现,那么我相信您的问题将会消失。这是因为Proxy$1确实实现了CatalogServiceInterface.

故事的寓意:如果您引用您的实现,请始终使用接口(因为如果您决定提供不同的实现(例如CatalogService2,它也实现CatalogServiceInterface了,您只能将其插入您CatalogAPIController的构造函数使用接口而不是类(本质上,这就是您指定@Transactional.

希望这是有道理的。

于 2013-10-28T00:54:21.843 回答
0

有两件事引起了我的注意

1.

@Transactinal

是错字还是要导入另一个注释,应该是@Transactional

2.

如果您已经定义了接口,为什么不使用它们?

代替

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

将其更改为

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

同样适用于 dao 接口。

我不明白将事务从一个地方转移到另一个地方之间的关系。看看有没有帮助

于 2013-10-25T14:59:31.493 回答
0

这是我根据您提供的详细信息所能想到的。我相信您的类路径中没有CGLIB库。因此,为了让 Spring 应用@Transactional行为,它使用 JDK 代理代理您的注释类。JDK 代理使用接口,它们不能代理基类。因此,代理的直接超类是java.lang.reflect.Proxy.

在这种情况下,您的CatalogServicebean 将被包装在一个代理中,其类类似于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没有工作,所以没有创建代理,因此 Spring 没有抱怨注入这个字段

@Autowired
private CatalogDAO catalogDAO;

在您的服务等级中。

一种可能的解决方案是按照 Luis 的建议进行操作,并将参数类型更改为接口作为 JDK 代理来实现接口,即。Proxy$1接口是为包装您的 bean 而生成的类实例的超类型。

另一种解决方案是CGLIB在您的类路径中提供 jar。Spring 会检测到它们并使用它们。然后它将能够通过基类而不是接口来代理您的类。你可以在这里找到图书馆。

不要忘记告诉 Spring 代理目标类

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
于 2013-10-27T19:30:46.920 回答