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

文章目录

    1. 错误
      1. 错误原因
      1. 解决方法
  • 3.1 第一种方法 * 3.2 第二种方法

1. 错误

1org.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' 2 3 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:392) 4 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) 5 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111) 6 at cn.wanghao.springSecurity.test.TestSpring.test(TestSpring.java:14) 7 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 8 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 9 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 10 at java.lang.reflect.Method.invoke(Method.java:497) 11 at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 12 at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 13 at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 14 at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 15 at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 16 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 17 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 18 at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 19 at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 20 at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 21 at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 22 at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 23 at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 24 at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 25 at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) 26 at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) 27 at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) 28 at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 29 30

2. 错误原因

spring对AOP有两种实现方式:

  1. 一种是JDK的动态代理。它是基于接口方式实现的,要求所代理的类是一个接口类或者继承了接口,对一般的类就无法代理,spring默认是这种;

例如mybatis实现dao层的代理就是直接代理的接口。

  1. 一种是CGLIB动态代理。通过设置proxy-target-class=“true”,可以启动CGLIBD的动态代理,CGLIB直接生成二进制码,使得普通类也可以实现AOP。

另外,如果同时对一个类使用动态代理和IOC创建对象,结果是只会实现动态代理而IOC不创建其对象。

mybatis整合到spring中,则创建的代理对象也会交给IOC,且代理对象的名字和IOC实例化对象名字的规范一样,也是类名首字母小写

如果是JDK动态代理,则生成的代理对象的类型是其接口类型;如果是cglib动态代理,则是该类的类型。

RoleService是service层的接口,RoleServiceImpl是其实现类,具体代码如下:

1@Service 2public class RoleServiceImpl implements RoleService { 3 @Autowired 4 private RoleDao roleDao; 5 6 @Override 7 public SysRole selectByID(Integer id) { 8 System.out.println("RoleServiceImpl..."); 9 return roleDao.selectByID(id); 10 } 11} 12 13

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

1<!-- 3. 配置 aop --> 2<aop:config> 3 <!-- 配置切入点表达式 --> 4 <aop:pointcut expression="execution(* cn.wanghao.springSecurity.service.impl.*.*(..))" id="pointcut1"/> 5 <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> 6</aop:config> 7 8

运行代码如下:

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

错误显示表明IOC容器中没有roleServiceImpl',但是有RoleServiceImpl'这个类的代理对象。而我使用的是spring默认的JDK动态代理,再结合上面的知识,你应该明白了,肯定是自己在哪里设置了RoleServiceImpl'的动态代理,但是你自己不知道。

通过排查,我发现我只有在AOP配置中使用了动态代理,结果发现果然对其设置了动态代理:execution(* cn.wanghao.springSecurity.service.impl.*.*(..))。而且使用的是JDK动态代理,而JDK动态代理最终该代理类是如下形式:

1public class $Proxy22 extends Proxy implements RoleService{ 2 ... 3} 4 5

动态生成的代理类的类型是被代理对象的接口类型,所以容器中的代理对象应该是名字为roleServiceImpl,但是类型为RoleService

3. 解决方法

3.1 第一种方法

既然,同时对一个类使用动态代理和IOC创建对象,结果是只会实现动态代理而IOC不创建其对象,那么我们可以选择使用·cglib·动态代理创建RoleServiceImpl类型的roleServiceImpl。

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

1<!-- 3. 配置 aop --> 2<aop:config> 3 <!-- 配置切入点表达式 --> 4 <aop:pointcut expression="execution(* cn.wanghao.springSecurity.service.impl.*.*(..))" id="pointcut1"/> 5 <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> 6</aop:config> 7<aop:aspectj-autoproxy proxy-target-class="true"/> 8 9

3.2 第二种方法

按照我们刚才分析的,去使用该对象。

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

然后就可以了:
在这里插入图片描述

代码交流 2021