SSM:but was actually of type 'com.sun.proxy.$Proxy23'

1. 錯誤

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'roleServiceImpl' is expected to be of type 'cn.wanghao.springSecurity.service.impl.RoleServiceImpl' but was actually of type 'com.sun.proxy.$Proxy22'

	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:392)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111)
	at cn.wanghao.springSecurity.test.TestSpring.test(TestSpring.java:14)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

2. 錯誤原因

spring對AOP有兩種實現方式:

  1. 一種是JDK的動態代理。它是基於接口方式實現的,要求所代理的類是一個接口類或者繼承了接口,對一般的類就無法代理,spring默認是這種;
    例如mybatis實現dao層的代理就是直接代理的接口。
  2. 一種是CGLIB動態代理。通過設置proxy-target-class=“true”,可以啓動CGLIBD的動態代理,CGLIB直接生成二進制碼,使得普通類也可以實現AOP。

另外,如果同時對一個類使用動態代理和IOC創建對象,結果是隻會實現動態代理而IOC不創建其對象。

mybatis整合到spring中,則創建的代理對象也會交給IOC,且代理對象的名字和IOC實例化對象名字的規範一樣,也是類名首字母小寫

如果是JDK動態代理,則生成的代理對象的類型是其接口類型;如果是cglib動態代理,則是該類的類型。

RoleService是service層的接口,RoleServiceImpl是其實現類,具體代碼如下:

@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleDao roleDao;

    @Override
    public SysRole selectByID(Integer id) {
        System.out.println("RoleServiceImpl...");
        return roleDao.selectByID(id);
    }
}

spring配置文件中的aop配置如下:

<!-- 3. 配置 aop -->
<aop:config>
    <!-- 配置切入點表達式 -->
    <aop:pointcut expression="execution(* cn.wanghao.springSecurity.service.impl.*.*(..))" id="pointcut1"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>

運行代碼如下:

@Test
public void test() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    RoleServiceImpl roleServiceImpl = ac.getBean("roleServiceImpl", RoleServiceImpl.class);
    SysRole sysRole = roleServiceImpl.selectByID(1);
    System.out.println(sysRole.toString());
}

錯誤顯示錶明IOC容器中沒有roleServiceImpl',但是有RoleServiceImpl'這個類的代理對象。而我使用的是spring默認的JDK動態代理,再結合上面的知識,你應該明白了,肯定是自己在哪裏設置了RoleServiceImpl'的動態代理,但是你自己不知道。

通過排查,我發現我只有在AOP配置中使用了動態代理,結果發現果然對其設置了動態代理:execution(* cn.wanghao.springSecurity.service.impl.*.*(..))。而且使用的是JDK動態代理,而JDK動態代理最終該代理類是如下形式:

public class $Proxy22 extends Proxy implements RoleService{
	...
}

動態生成的代理類的類型是被代理對象的接口類型,所以容器中的代理對象應該是名字爲roleServiceImpl,但是類型爲RoleService

3. 解決方法

3.1 第一種方法

既然,同時對一個類使用動態代理和IOC創建對象,結果是隻會實現動態代理而IOC不創建其對象,那麼我們可以選擇使用·cglib·動態代理創建RoleServiceImpl類型的roleServiceImpl

所以,直接在AOP配置的後面加上<aop:aspectj-autoproxy proxy-target-class="true"/>這一行代碼:

<!-- 3. 配置 aop -->
<aop:config>
    <!-- 配置切入點表達式 -->
    <aop:pointcut expression="execution(* cn.wanghao.springSecurity.service.impl.*.*(..))" id="pointcut1"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
<aop:aspectj-autoproxy  proxy-target-class="true"/>

3.2 第二種方法

按照我們剛纔分析的,去使用該對象。

@Test
public void test() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    RoleServiceImpl roleServiceImpl = ac.getBean("roleServiceImpl", RoleService.class);
    SysRole sysRole = roleServiceImpl.selectByID(1);
    System.out.println(sysRole.toString());
}

然後就可以了:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章