BeanNotOfRequiredTypeException 由于自动装配的字段

Posted

技术标签:

【中文标题】BeanNotOfRequiredTypeException 由于自动装配的字段【英文标题】:BeanNotOfRequiredTypeException due to autowired fields 【发布时间】:2013-01-08 16:03:52 【问题描述】:

我还是 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)

我有两个面向用户和管理员的滚动服务,并带有接口:

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);

这是 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;
    

这是 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>

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

Bean named 'adminService' must be of type [employee.service.impl.AdminServiceImpl], but was actually of type [$Proxy52]

我该如何解决?

我在控制器中使用 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";
     ....

【问题讨论】:

【参考方案1】:

您的代码中的某处必须像这样自动装配AdminServiceImpl

@Autowired
private AdminServiceImpl adminService;

要么几乎不依赖于接口:

@Autowired
private AdminService adminService;

或启用 CGLIB 代理。

类似问题

Autowired spring bean is not a proxy Fixing BeanNotOfRequiredTypeException on Spring proxy cast on a non-singleton bean? Getting Spring Error "Bean named 'x' must be of type [y], but was actually of type [$Proxy]" in Jenkins Original interface is lost in Spring AOP introduction

【讨论】:

@Serge:你可以自己解决,这是一个常见问题。只需查找AdminServiceImpl 类型的自动装配字段,我很确定您有一些。 IE。寻找您实际使用AdminServiceImpl 的地方。删除Impl 仅依赖接口。就是这样! 删除 Impl 以仅依赖接口。如果我了解你?我必须替换 AdminService 使用的所有 AdminServiceImpl。 @Serge:确实。事实上,如果你仍然依赖类,你为什么要分离类和接口呢? ...Impl 出现的唯一地方是在类定义中,没有其他地方。 告诉我有关“自动装配”的信息。我应该如何正确地自动装配字段?我应该在界面中这样做还是我做的一切都正确? 使用接口而不是实现并用@Qualifier注解来获得正确的类。救了我的命!【参考方案2】:

使用接口AdminService 而不是实现。

这个由注释引起的错误@TransactionalSpringRuntime 处为AdminService 做一个代理。

【讨论】:

或者如果您将@EnableTransactionManagement 添加到配置中,结果@Transactional 开始工作。对我来说【参考方案3】:

当您的服务类实现某个接口时,spring 默认使用 JDK 代理,这就是您得到该错误的原因,因此您可以通过接口使用 @Autowired 或启用 CGLIB 代理来解决该问题>.

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

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

【讨论】:

【参考方案4】:

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

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

就我而言,我的 applicationContext.xml 中有额外的 bean 配置。合并两个应用程序后出现问题。第二个定义了@Resource,它的成员变量名称与上面提到的第一个应用程序的bean名称相匹配。当然,第一个应用程序的 bean 配置不适合第二个应用程序通过 @Resource 包含的 bean。

【讨论】:

【参考方案5】:

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

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

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

【讨论】:

【参考方案6】:

确保您已启用 proxyTargetClass,例如:

@EnableTransactionManagement(proxyTargetClass = true)

【讨论】:

【参考方案7】:

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

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

class Abc

 @Autowire
 private Boy boy // remove @BoyImpl

.............
...................

【讨论】:

谢谢。伟大的。您的建议完全解决了我的问题。不知道为什么有人投了反对票。【参考方案8】:

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

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

@Component
public static class FooServiceImplMock extends FooServiceImpl 
    @Override
    protected void bar() 
        // do some specific loginc here 
    

但是当执行测试方法时

@Autowired
private Foo1ServiceImplMock foo1ServiceImplMock;

我得到以下错误

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'

原因:

FooServiceImpl 中有方法使用@Cacheable

@Cacheable("eventTypes")

我知道 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.

所以resolve的方式就是在spring应用上下文中明确指定使用CGLIB

 <cache:annotation-driven proxy-target-class="true"/>

【讨论】:

【参考方案9】:

我刚刚遇到这个问题,因为对现有类的测试开始失败并出现“预期类型...但实际上是类型“com.sun.proxy.$Proxy115”。

结果是我在添加到接口实现类的@Transactional 方法上使用了Intellij 的'pull method up [to interface]',而Intellij 决定将@Transactional 添加到接口方法中宣言。如果接口中只有一个 @Transactional 方法,那么它似乎搞砸了,导致这个错误。

【讨论】:

这对我帮助很大。我没有费心去看 IntelliJ 的“将方法拉到接口”实际上为我拉了什么。谢谢大佬

以上是关于BeanNotOfRequiredTypeException 由于自动装配的字段的主要内容,如果未能解决你的问题,请参考以下文章