深入解析Spring的proxy-target-class属性

一、proxy-target-class概念介绍

在Spring框架中,AOP被广泛用于各种类型的应用程序,用于将横切关注点与业务逻辑相分离,以提高应用程序的灵活性和可重用性。 Spring Framework通过动态代理或CGLIB库实现了AOP。 Spring AOP支持两种类型的代理:接口代理(默认情况下)和基于类的代理(使用proxy-target-class属性)。 接口代理要求目标对象实现至少一个接口。 基于类的代理(一般使用CGLIB库)则无需接口。相反,它们使用字节代码生成来创建目标对象的代理。 建议在以下情况下使用基于类的代理:

• 目标对象不实现任何接口

• 要从代理方法中调用另一个方法而不添加太多额外的代码,这可能是使用AOP的一个常见要求

• 希望代理位置更快(默认情况下,接口代理通常比基于类的代理慢)

二、proxy-target-class属性用法

Spring框架中提供了两种代理方式proxy-target-class和proxy-interface。proxy-target-class默认值为false,代表使用基于接口的JDK动态代理,此时目标对象的实现类必须至少实现一个接口;而如果proxy-target-class设置为true,则使用CGLIB方式的动态代理。

使用proxy-target-class的时候,目标类不需要实现任何接口也能被AOP代理拦截,Spring会选择CGLIB代理方式生成动态代理对象。

下面是具体的proxy-target-class使用示例

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
    @Bean
    public MyAspect myAspect() {
        return new MyAspect();
    }

    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
}

可以看到,通过@EnableAspectJAutoProxy(proxyTargetClass = true)开启CGLIB代理,默认为false,开启CGLIB代理需要导入CGLIB库。

三、CGLIB与JDK动态代理的区别

基于类的代理(即CGLIB)通常比基于接口的代理(即JDK)更快,因为它们直接操作字节码。但是,CGLIB不适用于代理类中的final方法 – 您不能在CGLIB类中覆盖final方法。 此外,使用CGLIB可能会将代理类的大小从一个接口代理的62字节增加到100字节或更多,而增加的码元数量可能对某些JIT编译器效果不佳。

下面是一个基于类的代理的简单示例

public class HelloWorld {
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloWorld.class);
        enhancer.setCallback(new MethodInterceptorImpl());
        HelloWorld proxy = (HelloWorld) enhancer.create();
        proxy.sayHello("World");
    }
}

class MethodInterceptorImpl implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before Method Invocation");
        Object returnObj = proxy.invokeSuper(obj, args);
        System.out.println("After Method Invocation");
        return returnObj;
    }
}

四、proxy-target-class的使用场景

proxy-target-class属性的最主要的使用场景就是处理没有实现任何接口的独立类的AOP。在Java中,我们往往缺乏混入委托等支持多重继承的特性,导致同一个对象分支下的逻辑散布于不同类中,这就是所谓的横切关注点。AOP可以解决这个问题,而对于没有实现接口的类来说,proxy-target-class就派上用场了。

五、总结

在Spring AOP中,默认情况下使用基于接口的动态代理,可以通过配置proxy-target-class属性来选择使用CGLIB提供的基于类的动态代理。对于那些不实现任何接口的类来说,proxy-target-class是必不可少的。

最后,需要注意的是,应谨慎使用proxy-target-class属性,在大型应用程序中或需要高性能的场景中,建议使用基于接口的动态代理来提高系统的性能。

原创文章,作者:WCKUW,如若转载,请注明出处:https://www.506064.com/n/317803.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
WCKUWWCKUW
上一篇 2025-01-11 16:28
下一篇 2025-01-11 16:28

相关推荐

  • JS Proxy(array)用法介绍

    JS Proxy(array)可以说是ES6中非常重要的一个特性,它可以代理一个数组,监听数据变化并进行拦截、处理。在实际开发中,使用Proxy(array)可以方便地实现数据的监…

    编程 2025-04-29
  • Spring Boot 集成 Jacoco

    本文将从以下几个方面介绍如何在 Spring Boot 中集成 Jacoco:1、Jacoco 概述;2、Spring Boot 集成 Jacoco 的配置;3、生成 Jacoco…

    编程 2025-04-29
  • Spring Boot中发GET请求参数的处理

    本文将详细介绍如何在Spring Boot中处理GET请求参数,并给出完整的代码示例。 一、Spring Boot的GET请求参数基础 在Spring Boot中,处理GET请求参…

    编程 2025-04-29
  • 如何通过增加 proxy 进行请求透传

    本文将从多个方面对增加 proxy 进行请求透传进行详细阐述。 一、proxy 的概念 Proxy(代理)是介于客户端和服务器之间的一种中间层服务器,将客户端发来的请求转发给服务器…

    编程 2025-04-29
  • Vant ContactList 增加属性的实现方法

    在使用前端UI框架Vant中的ContactList组件时,我们有时需要为此组件增加一些个性化的属性,来满足我们特定的需求。那么,如何实现ContactList组件的增加属性功能呢…

    编程 2025-04-29
  • 全面解读数据属性r/w

    数据属性r/w是指数据属性的可读/可写性,它在程序设计中扮演着非常重要的角色。下面我们从多个方面对数据属性r/w进行详细的阐述。 一、r/w的概念 数据属性r/w即指数据属性的可读…

    编程 2025-04-29
  • 如何在Spring Cloud中整合腾讯云TSF

    本篇文章将介绍如何在Spring Cloud中整合腾讯云TSF,并提供完整的代码示例。 一、TSF简介 TSF (Tencent Serverless Framework)是腾讯云…

    编程 2025-04-29
  • 如何使用Spring Boot ElasticJob进行配置覆盖

    本文将详细介绍如何使用Spring Boot ElasticJob进行配置覆盖。 一、目录结构 我们需要准备两个目录,分别是“elastic-job-lite-spring-boo…

    编程 2025-04-28
  • Spring Boot中使用DTO、Controller、Service、Mapper进行开发

    本文将介绍如何在Spring Boot中使用DTO、Controller、Service、Mapper等技术进行开发。 一、DTO DTO(Data Transfer Object…

    编程 2025-04-28
  • 使用PHP foreach遍历有相同属性的值

    本篇文章将介绍如何使用PHP foreach遍历具有相同属性的值,并给出相应的代码示例。 一、基础概念 在讲解如何使用PHP foreach遍历有相同属性的值之前,我们需要先了解几…

    编程 2025-04-28

发表回复

登录后才能评论