Spring动态代理问题

问题描述

获取Spring 某个class的bean报错

Spring 有两种方式实现代理:

  • 利用 JDK 动态代理机制 ,在运行时为实现了某些接口的类动态创建一个实现了同样接口的代理对象。
  • 使用 CGLIB,CGLIB 可以在运行期扩展Java类与实现Java接口,也就是说当一个类没有实现接口时,必须用 CGLIB 生成代理对象。
  • 所以,当 Spring 上下文中的一个实现了某个接口的 Bean 通过JDK 动态代理机制被代理时,代理类并不是继承了目标类,而是实现同样的接口。

也正因为如此,如果一个 Bean 通过接口注入时,可以成功被注入。但如果是通过真正的类注入,那么 Spring 将无法找到匹配这个类的 Definition——因为代理类并没有继承这个类。

以 Spring 中比较常见的事务管理为例,假设 ServiceA 中要注入 ServiceB,两个 Service 均标注了 @Transactional注解来进行事务管理,那么下面的注入方式是不会正常 work 的。


image.png

在通过一个beanName找到一个Bean之后,还在进一步判断找到的Bean类型是否跟beanName的Class的类型匹配,会调用isTypeMatch方法进行判断:
org.springframework.beans.factory.support.AbstractBeanFactory#isTypeMatch(java.lang.String, org.springframework.core.ResolvableType)

Jdk动态代理实现的类 isTypeMatch返回false

image.png

获取到的beanInstance时一个Jkd动态代理对象;

CGlib动态代理实现的类 isTypeMatch返回true

image.png

总结

现有一个接口Service,该接口有一个实现类ServiceA,
如果ServiceA是被JDK动态代理生成一个代理类JdkProxyServiceA,那么JdkProxyServiceA也实现了Service接口,但并不是继承ServiceA,Spring容器中存储的Bean就是JdkProxyServiceA,不会有一个ServiceA的Bean,所以调用applicationContext.getBean("ServiceA") 获取不到Bean

如果是CGLIB代理,生成的代理类是继承ServiceA的;

你可能感兴趣的:(Spring动态代理问题)