由于自动装配的字段导致BeanNotOfRequiredTypeException

Ser*_*rge 42 java annotations spring-mvc tomcat7

我还是Spring MVC的新手,在构建我的测试项目时,我从Tomcat日志中收到了这条消息:

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'divisionController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'adminService' must be of type [employee.service.impl.AdminServiceImpl], but was actually of type [$Proxy52]
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:307)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
    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:294)
    ...
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'adminService' must be of type [employee.service.impl.AdminServiceImpl], but was actually of type [$Proxy52]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:360)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
Run Code Online (Sandbox Code Playgroud)

我为用户和管理员提供了两个rolle服务:

package employee.service;

import employee.model.EmployeeDiv;
import employee.model.EmployeeInfo;
import employee.model.UserInfo;

import java.util.List;

/**
 *
 * @author serge
 */

public interface AdminService extends UserService {

     //  !!!! for register & udate of Employee use String type birthday !!!!

    /*
     * Employee
     */
    public EmployeeInfo registerEmployee(EmployeeInfo employeeInfo);

    public EmployeeInfo updateEmployee(EmployeeInfo employeeInfo);

    public EmployeeInfo findEmployeeByID(Integer id);   

    /*
     * Division
     */
    public EmployeeDiv registerDivision(EmployeeDiv division);

    public EmployeeDiv updateDivision(EmployeeDiv division);

    public List<EmployeeDiv> findAllDivisions();

    public List<EmployeeDiv> findDivisionsByName(EmployeeDiv division);

    public EmployeeDiv findDivisionsById(Integer id);

    /*
     * Login
     */
    public UserInfo registerUser(UserInfo user);

    public UserInfo updateUser(UserInfo user);

    public List<UserInfo> findAllUsesrs();

    public List<UserInfo> findUsesrByLogin(UserInfo user);

    public UserInfo findUsesrById(Integer id);
}
Run Code Online (Sandbox Code Playgroud)

这是AdminServiceImpl:

package employee.service.impl;

import employee.DAO.EmployeeDivDAO;
import employee.DAO.EmployeeInfoDAO;
import employee.DAO.UserDAO;
import employee.model.EmployeeDiv;
import employee.model.EmployeeInfo;
import employee.model.UserInfo;
import employee.service.AdminService;
import employee.validation.ParsingDate;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author serge
 *
 * Admin level
 *
 * Service for processing employee, divisions, userslogin
 */

//@Repository("adminService")
@Service("adminService")
@Transactional
public class AdminServiceImpl extends UserServiceImpl implements AdminService {

    protected static Logger adminLogger = Logger.getLogger("service");
    private EmployeeDivDAO emplDivDAO;
    private UserDAO userDAO;
    private EmployeeInfoDAO emplInfoDAO;

    @Autowired
    @Override
    public void setEmployeeDao(EmployeeInfoDAO emplInfoDAO) {
        this.emplInfoDAO = emplInfoDAO;
    }

    @Autowired
    public void setEmployeeDao(EmployeeDivDAO emplDivDAO) {
        this.emplDivDAO = emplDivDAO;
    }

    @Autowired
    public void setUserDao(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public AdminServiceImpl() {

        initTestEmployee();
    }

    /**
     * Initialize EmployeeInfo test
     */
    @Transactional
    @Secured("ROLE_ADMIN")
    private EmployeeInfo initTestEmployee() {

        adminLogger.debug("saving testEmployee");

        EmployeeInfo employeeInfo = new EmployeeInfo();
        ParsingDate date = new ParsingDate();
        employeeInfo.setFirstName("Petr");
        employeeInfo.setLastName("Ivanenko");
        employeeInfo.setEmpDiv("second");
        employeeInfo.setBirthdate(date.parseDate("1981-10-03"));
        employeeInfo.setSalary(3500);
        employeeInfo.setActive(true);

        return employeeInfo;
    }

    /**
     * registrating new Employee Information
     *
     * @return EmployeeInfo object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeInfo registerEmployee(EmployeeInfo employeeInfo) {

        adminLogger.debug("registrating new Employee");

        try {

            emplInfoDAO.save(employeeInfo);

        } catch (NullPointerException e) {
        }
        return employeeInfo;
    }

    /**
     * updating Employee Information
     *
     * @return EmployeeInfo object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeInfo updateEmployee(EmployeeInfo employeeInfo) {

        adminLogger.debug("updating Employee with id: " + employeeInfo.getId());
        try {

            emplInfoDAO.update(employeeInfo);

        } catch (NullPointerException e) {
        }
        return employeeInfo;
    }

    /**
     * Retrieving Employee Information by id 
     *
     * @return EmployeeInfo object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeInfo findEmployeeByID(Integer id) {

        adminLogger.debug("Retrieving Employee with id= " + id);
        EmployeeInfo employeeInfo = new EmployeeInfo();
        employeeInfo.setId(id);
        emplInfoDAO.find(employeeInfo);
        return employeeInfo;
    }

    /**
     * registrating new Employee Division
     *
     * @return EmployeeDiv object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeDiv registerDivision(EmployeeDiv division) {

        adminLogger.debug("registrating new Division");
        try {

            emplDivDAO.save(division);

        } catch (NullPointerException e) {
        }
        return division;
    }

    /**
     * updating Employee Division
     *
     * @return EmployeeDiv object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeDiv updateDivision(EmployeeDiv division) {

        adminLogger.debug("updating Division with id: " + division.getId());
        try {

            emplDivDAO.update(division);

        } catch (NullPointerException e) {
        }
        return division;
    }

    /**
     * Retrieving all Employee Divisions
     *
     * @return List of EmployeeDiv objects
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public List<EmployeeDiv> findAllDivisions() {

        adminLogger.debug("Retrieving all divisions");
        return emplDivDAO.findAll();
    }

    /**
     * Retrieving all Employee Divisions by name
     *
     * @return List of EmployeeDiv objects
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public List<EmployeeDiv> findDivisionsByName(EmployeeDiv division) {
        String empDiv = "empDiv";

        adminLogger.debug("Retrieving Divisions by name: " + division.getEmpDiv());
        return emplDivDAO.findAllByParam(empDiv, division.getEmpDiv());
    }

     /**
     * Retrieving Employee Divisions by id 
     *
     * @return EmployeeDiv object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public EmployeeDiv findDivisionsById(Integer id) {

        adminLogger.debug("Retrieving Division with id= " + id);
        EmployeeDiv employeeDiv = new EmployeeDiv();
        employeeDiv.setId(id);
        emplInfoDAO.find(employeeDiv);
        return employeeDiv;
    }

    /**
     * registrating new User Information
     *
     * @return UserInfo object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public UserInfo registerUser(UserInfo user) {

        adminLogger.debug("registrating new User");
        try {

            userDAO.save(user);

        } catch (NullPointerException e) {
        }
        return user;
    }

    /**
     * updating new User Information
     *
     * @return UserInfo object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public UserInfo updateUser(UserInfo user) {

        adminLogger.debug("updating User with id: " + user.getId());
        try {

            userDAO.update(user);

        } catch (NullPointerException e) {
        }
        return user;
    }

    /**
     * retriviting all Users 
     *
     * @return List of UserInfo objects
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public List<UserInfo> findAllUsesrs() {

        adminLogger.debug("Retrieving all Users");
        return userDAO.findAll();
    }

    /**
     * retriving all Users by login
     *
     * @return List of UserInfo objects
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public List<UserInfo> findUsesrByLogin(UserInfo user) {
        String login = "login";

        adminLogger.debug("Retrieving User with login: " + login);
        return userDAO.findAllByParam(login, user.getLogin());
    }

    /**
     * Retrieving Employee Divisions by id 
     *
     * @return EmployeeDiv object
     */
    @Override
    @Transactional
    @Secured("ROLE_ADMIN")
    public UserInfo findUsesrById(Integer id) {

        adminLogger.debug("Retrieving Division with id= " + id);
        UserInfo userInfo = new UserInfo();
        userInfo.setId(id);
        emplInfoDAO.find(userInfo);
        return userInfo;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

    <!-- Activates annotations -->

    <context:annotation-config />

    <!-- Scans for annotated components in base-package-->

    <context:component-scan base-package="employee" />

    <bean class="employee.service.impl.AdminServiceImpl"/>
    <bean class="employee.service.impl.UserServiceImpl"/>
    <!--bean class="employee.DAO.impl.EmployeeInfoDAOImpl"/>
    <bean class="employee.DAO.impl.EmployeeDivDAOImpl"/>
    <bean class="employee.DAO.impl.UserDAOImpl"/-->

    <!-- for Spring Jackson JSON support  -->

    <mvc:annotation-driven/>

    <!-- Shared Hibernate SessionFactory in a Spring application context. -->

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>

        <!--property name="dataSource">
            <ref bean="dataSource"/>
        </property-->

        <property name="annotatedClasses">
            <list>
                <value>employee.model.UserInfo</value>
                <value>employee.model.EmployeeInfo</value>
                <value>employee.model.EmployeeDiv</value>
            </list>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!-- for database, imports the properties from database.properties -->

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:database.properties"/>
    </bean>
</beans>
Run Code Online (Sandbox Code Playgroud)

请告诉我这个bean名称有什么问题,我明白是AOP问题:

Bean named 'adminService' must be of type [employee.service.impl.AdminServiceImpl], but was actually of type [$Proxy52]
Run Code Online (Sandbox Code Playgroud)

我该怎么办呢?

我在控制器中使用AdminServiceImpl:

package employee.controller;

import employee.model.EmployeeDiv;
import employee.service.impl.AdminServiceImpl;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;

/**
 * @author serge
 *
 * Handles and retrieves division related requests
 */
@Controller
@RequestMapping("/division")
public class DivisionController {

    protected static Logger logger = Logger.getLogger("controller");
    @Resource(name = "adminService")
    private AdminServiceImpl adminService;

    /**
     * Handles and retrieves a /WEB-INF/jsp/divisionpage.jsp
     *
     * containing all division
     *
     * @return the name of the JSP page
     */
    @RequestMapping(method = RequestMethod.GET)
    public String getAllPage(Model model) {
        logger.debug("Received request to show all division page");

        // Retrieve all division and attach to model 
        model.addAttribute("division", adminService.findAllDivisions());
        return "divisionpage";
    } ....
Run Code Online (Sandbox Code Playgroud)

Tom*_*icz 93

在代码中的某个地方,你必须AdminServiceImpl像这样自动装配:

@Autowired
private AdminServiceImpl adminService;
Run Code Online (Sandbox Code Playgroud)

要么勉强依赖于界面:

@Autowired
private AdminService adminService;
Run Code Online (Sandbox Code Playgroud)

或启用CGLIB代理.

类似的问题

  • @Serge:你可以自己解决,这是一个常见的问题.只需查看"AdminServiceImpl"类型的自动装配字段,我很确定你有一些.即寻找实际使用`AdminServiceImpl`的地方.删除`Impl`仅依赖于接口.而已! (5认同)
  • 使用接口代替实现,并使用@Qualifier注释以获得正确的类.救了我的命! (3认同)
  • @Serge:的确如此.事实上,如果你仍然依赖于课程,为什么要将类和接口分开呢?`... Impl`出现的唯一地方是在类定义中,没有其他地方. (2认同)

小智 23

使用接口AdminService而不是工具.

由Annotation引起的这个错误@Transactional,Spring代表AdminServiceat Runtime.


Kha*_*mon 11

确保您已启用 proxyTargetClass,例如:

@EnableTransactionManagement(proxyTargetClass = true)
Run Code Online (Sandbox Code Playgroud)


Chr*_*ala 9

当您的服务类实现某个接口时,默认情况下spring会接受JDK的代理,这就是您收到该错误的原因,因此无论是通过接口使用@Autowired还是启用CGLIB代理,您都可以解决该问题.

我解决了在我的spring应用程序上下文中使用proxy-target-class属性启用CGLIB代理的问题

<tx:annotation-driven proxy-target-class="true"
        transaction-manager="transactionManager" />
Run Code Online (Sandbox Code Playgroud)


Jim*_*mmy 8

我在一些@SpringBootTest测试端点的类中也遇到了这个问题。端点依赖于具有@Transactional一些方法的数据库服务。

由于@Transactional,Spring 会拦截它并创建一个代理类,因此 Spock(或 junit)将很难注入正确的模拟。

我的解决方法是将数据库服务下推一层,并在中间层周围进行简单的 Spock 测试,而中间层不受此影响。


小智 7

我遇到了同样的问题,但我通过以下解决方法解决了问题:

请将您的实现类替换为接口。例如:

class Abc
{
 @Autowire
 private Boy boy // remove @BoyImpl

.............
...................
}
Run Code Online (Sandbox Code Playgroud)


fis*_*one 5

在Google搜索我的问题时,我发现了许多与此问题类似的问题。但是,就我而言,我已经使用了一个接口。所以我认为这可能对其他人有帮助:

如果您有两个具有相同名称的bean,也可能会出现此异常!

就我而言,我的applicationContext.xml中具有其他bean配置。我合并两个应用程序后出现了问题。第二个定义了a,@Resource并且其成员变量名称与上述第一个应用程序的bean名称匹配。当然,第一个应用程序的Bean配置不适合@Resource第二个应用程序所包含的Bean 。


zhu*_*wei 5

我在执行单元测试时也遇到了这个问题

我创建了一个模拟服务来实现真正的服务来覆盖某些方法,以便于测试某些用户案例

@Component
public static class FooServiceImplMock extends FooServiceImpl {
    @Override
    protected void bar() {
        // do some specific loginc here 
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当执行测试方法时

@Autowired
private Foo1ServiceImplMock foo1ServiceImplMock;
Run Code Online (Sandbox Code Playgroud)

我收到以下错误

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'fooServiceImplTest.FooServiceImplMock' is expected to be of type 'com.foo.business.impl.FooServiceImplTest$FooServiceImplMock' but was actually of type 'com.sun.proxy.$Proxy97'
Run Code Online (Sandbox Code Playgroud)

原因:

FooServiceImpl中有一个方法使用了@Cacheable

@Cacheable("eventTypes")
Run Code Online (Sandbox Code Playgroud)

从 EnableCaching 的 javadoc 我知道

org.springframework.cache.annotation.EnableCaching 
boolean proxyTargetClass()

Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies. The default is false.
Run Code Online (Sandbox Code Playgroud)

所以解决方式是明确指定在spring应用程序上下文中使用CGLIB

 <cache:annotation-driven proxy-target-class="true"/>
Run Code Online (Sandbox Code Playgroud)


JL_*_*_SO 5

当对现有类的测试开始失败时,我刚刚遇到了这个问题,并显示“预期属于类型...但实际上属于“com.sun.proxy.$Proxy115”类型。

结果是,我在添加到接口的实现类中的 @Transactional 方法上使用了 Intellij 的“上拉方法[到接口]”,并且 Intellij 决定将 @Transactional 添加到接口方法声明中。如果接口中只有一个 @Transactional 方法,那么它似乎会把事情搞砸,从而导致此错误。