Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理

这篇具有很好参考价值的文章主要介绍了Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家都知道,AOP 底层是动态代理,而 Java 中的动态代理有两种实现方式:

  • 基于 JDK 的动态代理

  • 基于 Cglib 的动态代理

这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口,而基于 Cglib 的动态代理并不需要被代理对象有接口。

那么,Spring 中的 AOP 是怎么实现的?是基于 JDK 的动态代理还是基于 Cglib 的动态代理?

1. Spring

先来说结论,Spring 中的动态代理,具体用哪种,分情况:

  • 如果代理对象有接口,就用 JDK 动态代理,否则就是 Cglib 动态代理。

  • 如果代理对象没有接口,那么就直接是 Cglib 动态代理。

来看看这段来自官方文档的说辞:

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理,# spring,java,spring boot,开发语言

可以看到,即使在最新版的 Spring 中,依然是如上策略不变。即能用 JDK 做动态代理就用 JDK,不能用 JDK 做动态代理就用 Cglib,即首选 JDK 做动态代理。

2. Spring Boot 

Spring Boot 和 Spring 一脉相承,那么在动态代理这个问题上是否也是相同的策略呢?抱歉,这个还真不一样。

Spring Boot 中对这个问题的处理,以 Spring Boot2.0 为节点,前后不一样。

在 Spring Boot2.0 之前,关于 Aop 的自动化配置代码是这样的(Spring Boot 1.5.22.RELEASE):

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass = false)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
   matchIfMissing = true)
 public static class JdkDynamicAutoProxyConfiguration {

 }

 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass = true)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
   matchIfMissing = false)
 public static class CglibAutoProxyConfiguration {

 }

}

可以看到,这个自动化配置主要是在讨论 application.properties 配置文件中的 spring.aop.proxy-target-class 属性的值。

具体起作用的是 @ConditionalOnProperty 注解,关于这个注解中的几个属性,也来稍微说下:

  • prefix:配置文件的前缀。

  • name:配置文件的名字,和 prefix 共同组成配置的 key。

  • having:期待配置的值,如果实际的配置和 having 的值相同,则这个配置就会生效,否则不生效。

  • matchIfMissing:如果开发者没有在 application.properties 中进行配置,那么这个配置类是否生效。

基于如上介绍,很容易看出:

  • 如果开发者设置了 spring.aop.proxy-target-class 为 false,则使用 JDK 代理。

  • 如果开发者设置了 spring.aop.proxy-target-class 为 true,则使用 Cglib 代理。

  • 如果开发者一开始就没配置 spring.aop.proxy-target-class 属性,则使用 JDK 代理。

这是 Spring Boot 2.0 之前的情况。

再来看看 Spring Boot 2.0(含)之后的情况(Spring Boot 2.0.0.RELEASE):

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
  AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass = false)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
 public static class JdkDynamicAutoProxyConfiguration {

 }

 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass = true)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
 public static class CglibAutoProxyConfiguration {

 }

}

可以看到,大部分配置都是一样的,有一个地方不太相同,那就是 matchIfMissing 属性的值。可以看到,从 Spring Boot2.0 开始,如果用户什么都没有配置,那么默认情况下使用的是 Cglib 代理。

3. 实践

最后可以写一个简单的例子验证一下上面的理论。

首先创建一个 Spring Boot 项目(本案例使用最新版 Spring Boot,即默认使用 Cglib 代理),加入三个依赖即可,如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

接下来创建一个 IUserService 接口,如下:

public interface IUserService {

    void hello();

}

然后再来创建一个该接口的实现类:

@Service
public class UserServiceImpl implements IUserService {

    @Override
    public void hello() {

    }

}

方法不用实现。

再来一个简单的切面:

@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {

    @Before("execution(* org.lzx.demo.UserServiceImpl.*(..))")
    public void before(JoinPoint jp) {
        System.out.println("jp.getSignature().getName() = " + jp.getSignature().getName());
    }

}

最后再来一个简单的测试方法,注入 IUserService 实例:

@RestController
public class HelloController {

    @Autowired
    private IUserService iUserService;

    @GetMapping("/hello")
    public void hello() {
        iUserService.hello();
    }

}

DBUEG 运行一下,就可以看到 IUserService 是通过 Cglib 来代理的。

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理,# spring,java,spring boot,开发语言

如果我们想用 JDK 来代理,那么只需要在 application.properties 中添加如下配置即可:

spring.aop.proxy-target-class=false

添加完成后,重新 DEBUG,如下图:

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理,# spring,java,spring boot,开发语言

可以看到,已经使用了 JDK 动态代理了。

如果用的是 Spring Boot 1.5.22.RELEASE 这个版本,那么即使不在 application.properties 中添加配置,默认也是 JDK 代理。 

4. 小结

总结一下:

  1. Spring 中的 AOP,有接口就用 JDK 动态代理,没有接口就用 Cglib 动态代理。

  2. Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。文章来源地址https://www.toymoban.com/news/detail-652215.html

到了这里,关于Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java中的静态代理、jdk动态代理以及CGLIB 动态代理

    代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能 那以下文章主要谈三种代理模式, 分别是静态代理,jdk的动态代理,cglib的动

    2024年02月11日
    浏览(44)
  • Spring之CGLIB和JDK动态代理底层实现

    目录 CGLIB 使用示例-支持创建代理对象,执行代理逻辑 使用示例-多个方法,走不同的代理逻辑 JDK动态代理 使用示例-支持创建代理对象,执行代理逻辑 ProxyFactory 如何自动在CGLIB和JDK动态代理转换 使用示例-使用CGLIB代理方式 使用示例-使用JDK动态代理方式 Spring会自动在JDK动态

    2024年04月25日
    浏览(31)
  • Spring学习(五):一篇讲清楚动态代理(jdk和cglib)的使用、原理和源码

    目录 一、jdk动态代理的基本使用 二、cglib动态代理的基本使用 2.1 方法一:method.invoke() 方法反射调用 2.2 方法二(spring使用的这个方法): methodProxy.invoke() 2.3 方法三:methodProxy.invokeSuper() 三、jdk实现代理的原理  四、jdk实现代理的源码 五、jdk对代理的优化  六、cglib实现动

    2023年04月14日
    浏览(46)
  • 动态代理JDK与cglib的区别之:如何处理被代理方法中的This调用

    关于 JDK 与 cglib 动态代理的使用不是本文关注的重点,如有不清楚的同学可以查询相关资料进行了解。本文主要是要讲一下在面对方法存在嵌套调用时 JDK 与 cglib 动态代理的区别以及原因。 先看下测试代码,注意下 TestProxyJDKImpl 的 test1 方法调用了 test2 方法即可。 为了更好说

    2024年02月09日
    浏览(36)
  • JDK 动态代理(Spring AOP 的原理)(面试重点)

            也叫委托模式.定义:为其他对象提供⼀种代理以控制对这个对象的访问.它的作⽤就是通过提供⼀个代理类,让我们 在调⽤⽬标⽅法的时候,不再是直接对⽬标⽅法进⾏调⽤,⽽是通过代理类间接调⽤,在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,⽽代

    2024年01月22日
    浏览(41)
  • JDK动态代理和CGLIB动态代理

    JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的

    2024年02月07日
    浏览(45)
  • 【动态代理】JDK动态代理与cglib动态代理源码解析

    UserService ,接口类 UserServiceImpl ,实现类 使用代理,测试效果。 控制台输出: Proxy#newProxyInstance ,生成代理类的实例。 核心在于 getProxyClass0 ,生成代理类的类信息 使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例 WeakCache#get ProxyClassFactory#apply ,实现了

    2024年02月04日
    浏览(45)
  • 代理模式:静态代理+JDK/CGLIB 动态代理

    代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。 代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法

    2024年02月13日
    浏览(37)
  • 通俗易懂 快速理解 JDK动态代理 和 cglib动态代理

    动态代理的实现方案有两种, JDK动态代理 和 CGLIB动态代理 ,区别在于JDK自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。 JDK动态代理 :JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求 代理对象和目标对象实现同样的接口 (兄

    2024年02月08日
    浏览(50)
  • SpringAOP-说说 JDK动态代理和 CGLIB 代理

    Spring 的 AOP 是通过动态代理来实现的,动态代理主要有两种方式 JDK 动态代理和 Cglib 动态代理,这两种动态代理的使用和原理有些不同。 JDK 动态代理 Interface :JDK动态代理是基于接口的代理,它要求目标类实现一个接口。 InvocationHandler :InvocationHandler 是一个接口,可以通过

    2024年01月18日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包