一文读懂 Spring 动态代理

admin 2025年1月22日11:04:05评论6 views字数 3905阅读13分1秒阅读模式

在 Java 开发的奇妙世界里,Spring 框架就像一位超级英雄,在各种企业级项目中 “大显身手”,帮我们解决了数不清的难题。而 Spring 动态代理作为 Spring 框架中的一项 “秘密武器”,更是为开发者们带来了无限可能。今天,就让我们一起揭开 Spring 动态代理的神秘面纱,看看它到底有什么神奇之处!

  • 什么是动态代理

在深入了解 Spring 动态代理之前,我们得先搞清楚什么是代理。想象一下,你想买一张热门演唱会的门票,但又怕自己抢不到,这时候你就可以找一个 “靠谱” 的票务代理帮你抢票。这个票务代理就相当于我们程序中的代理对象,它帮你去做一些你不太方便或者不想直接做的事情。在程序里,代理模式就是为其他对象提供一个 “代理替身”,通过这个替身来控制对目标对象的访问。简单来说,代理对象就像是一座桥梁,把客户端和目标对象连接起来,客户端不用直接和目标对象打交道,而是通过代理对象来间接访问。

代理分为静态代理和动态代理。静态代理就像是提前定制好的衣服,在编译期就已经把代理类的代码写死了,一旦做好,就很难修改。而动态代理则像是一件可以根据你的身材随时调整的 “智能衣服”,它是在程序运行的时候,根据实际需要动态生成代理类及其实例的。动态代理最大的好处就是,我们不用去修改目标对象的代码,就能轻松地给它添加各种 “额外功能”,就像给手机安装各种 APP 一样,想装什么功能就装什么功能,这大大提高了代码的可维护性和扩展性,是不是很厉害?

  • Spring 动态代理的原理

Spring 动态代理主要是借助 Java 的反射机制来实现的,它就像一个 “魔法工厂”,能根据我们的需求生产出各种神奇的代理对象。Spring 提供了两种 “魔法配方” 来制作代理对象,分别是 JDK 动态代理和 CGLIB 动态代理。

(一)JDK 动态代理

JDK 动态代理是 Java 自带的 “魔法”,它就像一个挑剔的 “小工匠”,要求目标对象必须实现至少一个接口。为什么呢?因为 JDK 动态代理是通过接口来创建代理对象的,就像你要制作一把钥匙,必须先有一个锁的模具(接口)才行。

JDK 动态代理有两个核心类,一个是Proxy,另一个是InvocationHandler。InvocationHandler就像是一个 “幕后指挥官”,它是一个接口,我们需要实现它的invoke方法,在这个方法里编写我们的代理逻辑。比如说,你想在调用目标对象的方法之前先检查一下权限,或者在方法调用之后记录一下日志,这些都可以在invoke方法里实现。

而Proxy类则像是一个 “神奇的工厂”,它的newProxyInstance方法就是生产代理对象的 “魔法机器”。我们只需要给它传入类加载器(就像是工厂的能源供应)、目标对象实现的接口数组(就像是制作钥匙的模具)以及InvocationHandler实例(就像是工厂的指挥官),它就能帮我们生成一个代理对象。当我们调用这个代理对象的方法时,其实就像是按下了工厂的启动按钮,真正执行的是InvocationHandler的invoke方法。在这个方法里,我们可以先做一些 “准备工作”(前置处理),然后通过反射调用目标对象的实际方法,最后再做一些 “收尾工作”(后置处理)。

(二)CGLIB 动态代理

CGLIB(Code Generation Library)是一个超级强大且高性能的代码生成库,它就像一个 “万能的工匠”,即使目标对象没有实现接口,它也能施展 “魔法” 创建代理对象。

CGLIB 是怎么做到的呢?它采用了继承的方式,就像让一个孩子继承父母的优点一样,CGLIB 会在运行时生成目标类的一个子类,这个子类就像是目标类的 “超级模仿者”,它重写了目标类的所有非 final 方法,并且在这些方法中巧妙地织入了我们的代理逻辑。

CGLIB 动态代理的核心类是Enhancer,它就像是 CGLIB 的 “魔法棒”。我们只需要设置Enhancer的父类为目标类(告诉它要模仿谁),再设置回调函数(类似于 JDK 动态代理中的InvocationHandler,它是代理逻辑的执行者),然后轻轻挥动 “魔法棒”(调用create方法),就能创建出一个代理对象啦!

  • Spring 动态代理的例子

光说不练假把式,下面我们就通过具体的代码示例来看看 Spring 动态代理是怎么 “大显神通” 的。

publicinterfaceUserService {voidaddUser();}

然后,我们实现这个接口的目标类UserServiceImpl,它就像是一个 “勤劳的小蜜蜂”,负责具体执行任务。

publicclassUserServiceImplimplementsUserService {@OverridepublicvoidaddUser() {System.out.println("添加用户");    }}

接着,我们要实现InvocationHandler接口,它就像是一个 “交通指挥员”,负责指挥代理对象的行动。

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;publicclassUserServiceInvocationHandlerimplementsInvocationHandler {privateObject target;publicUserServiceInvocationHandler(Object target) {this.target = target;    }@OverridepublicObjectinvoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法调用前的处理,比如检查权限");Object result = method.invoke(target, args);System.out.println("方法调用后的处理,比如记录日志");return result;    }}

最后,我们来测试 JDK 动态代理,就像是在舞台上表演一场魔术。

import java.lang.reflect.Proxy;publicclassJDKProxyTest {publicstaticvoidmain(String[] args) {UserService target = newUserServiceImpl();UserServiceInvocationHandler handler = newUserServiceInvocationHandler(target);UserService proxy = (UserServiceProxy.newProxyInstance(                target.getClass().getClassLoader(),                target.getClass().getInterfaces(),                handler);        proxy.addUser();    }}

二)CGLIB 动态代理示例

首先,我们定义一个没有实现接口的目标类OrderService,它就像是一个 “独行侠”,自己做自己的事情。

publicclassOrderService {publicvoidaddOrder() {        System.out.println("添加订单");    }}

然后,我们实现 CGLIB 的回调接口MethodInterceptor,它就像是 CGLIB 的 “智囊团”,为代理对象出谋划策。

import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;publicclassOrderServiceMethodInterceptorimplementsMethodInterceptor {@OverridepublicObjectintercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("方法调用前的处理,比如检查库存");Object result = methodProxy.invokeSuper(o, objects);System.out.println("方法调用后的处理,比如更新订单状态");return result;    }}

最后,我们来测试 CGLIB 动态代理,见证 “魔法” 的时刻。

import net.sf.cglib.proxy.Enhancer;publicclassCGLIBProxyTest {publicstaticvoidmain(String[] args) {Enhancer enhancer = newEnhancer();        enhancer.setSuperclass(OrderService.class);        enhancer.setCallback(newOrderServiceMethodInterceptor());OrderService proxy = (OrderService) enhancer.create();        proxy.addOrder();    }}

原文始发于微信公众号(代码小铺):一文读懂 Spring 动态代理

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月22日11:04:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   一文读懂 Spring 动态代理https://cn-sec.com/archives/3644474.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息