私はまだ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)
私はユーザーと管理者のために2つのロールサービスがあります:
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";
} ....
コードのどこかに、次のようにAdminServiceImpl
を自動配線する必要があります。
@Autowired
private AdminServiceImpl adminService;
インターフェースにほとんど依存しない:
@Autowired
private AdminService adminService;
または有効化されたCGLIBプロキシ。
実装ではなく、インターフェースAdminService
を使用します。
このエラーは、注釈@Transactional
、Spring
は、AdminService
でRuntime
のプロキシを作成します。
サービスクラスがインターフェイスを実装すると、SpringはデフォルトでJDKによるプロキシを取得します。そのため、このエラーが発生します。そのため、インターフェイスで@Autowiredを使用するか、CGLIBプロキシを有効にしても問題を解決できます。
春のアプリケーションコンテキストでproxy-target-class属性を使用してCGLIBプロキシを有効にする問題を解決しました
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
私の問題をグーグルで検索すると、この質問に似た質問がたくさん見つかりました。ただし、私の場合は、すでにインターフェイスを使用しています。だから私はこれが他の人にとって役立つかもしれないと思った:
私の場合、applicationContext.xmlに追加のBean設定がありました。この問題は、2つのアプリケーションを統合した後に現れました。 2番目のものは@Resource
を定義し、そのメンバー変数名は、前述の最初のアプリケーションのBean名と一致しました。もちろん、最初のアプリケーションのBean構成は、2番目のアプリケーションによって@Resource
を介して含まれるBeanに適合しませんでした。
私は同じ問題に直面していますが、次の回避策で問題を解決しました:
実装クラスをインターフェースに置き換えてください。例えば:
class Abc
{
@Autowire
private Boy boy // remove @BoyImpl
.............
...................
}
エンドポイントをテストしているいくつかの@SpringBootTest
クラスでもこの問題が発生しました。エンドポイントは、いくつかのメソッドで@Transactional
を持つDBサービスに依存していました。
@Transactional
により、Springはそれをインターセプトしてプロキシクラスを作成するため、Spock(またはjunit)は正しいモックの注入に苦労します。
私の回避策は、DBサービスを1つのレイヤーにプッシュダウンし、これにより影響を受けない中間レイヤーの周りに単純なSpockテストを行うことでした。
また、ユニットテストを実行するときに問題に遭遇しました
実際のサービスを実装する模擬サービスを作成して、いくつかのユーザーケースを簡単にテストできるようにメソッドをオーバーライドしました
@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'
理由:
@Cacheableで使用されるFooServiceImplにメソッドがあります
@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.
したがって、解決方法は、春のアプリケーションcontenxtで使用CGLIBを明示的に指定することです
<cache:annotation-driven proxy-target-class="true"/>