当前位置: 首页 > news >正文

Java 中的代理模式

目录

Java 的静态代理与动态代理

一. 静态代理

1. 概念

2. 实现

(1) 定义目标接口

(2) 定义目标类

(3) 定义代理类

(4) 使用代理类

二. 动态代理

1. 概念

2. JDK 动态代理

(1) 定义接口

(2) 接口的实现类

(3) 生成代理对象

(4) 使用代理类

3. CGLIB 动态代理

(1) 添加 CGLIB 依赖

(2) 定义目标类 (无需实现接口)

(3) 实现 MethodInterceptor 接口

(4) 使用代理类


Java 的静态代理与动态代理

一. 静态代理

1. 概念

静态代理是代理模式中最基础的实现方式.

静态代理要求 代理类在编译期就已确定. 并且 代理类与目标类 实现相同的接口 或 继承相同父类. 通过静态代理, 我们可以在不修改目标类代码的情况下, 对其方法进行增强 (添加 日志, 权限校验 等功能).

静态代理的核心是:

  • 定义一个目标接口, 包含需要被代理的方法.

  • 目标类实现该接口, 提供具体的业务逻辑.

  • 代理类也实现该接口, 内部持有目标对象的引用, 在调用目标方法前后添加增强逻辑.

外界通过调用代理类的方法, 间接调用目标类的方法, 从而实现功能增强.

2. 实现
(1) 定义目标接口
/*** IAnimal 接口* (这里写要被代理的方法)*/
public interface IAnimal {/*** 吃饭*/public abstract void eat();
​/*** 睡觉*/public abstract void sleep();
}

(2) 定义目标类
/*** 目标类 Animal*/
public class Animal implements IAnimal{
​@Overridepublic void eat() {System.out.println("吃吃吃");}
​@Overridepublic void sleep() {System.out.println("睡睡睡");}
}

(3) 定义代理类
/*** 代理类 AnimalProxy*/
public class AnimalProxy implements IAnimal {
​private final Animal animal;
​public AnimalProxy(Animal animal) {this.animal = animal;}@Overridepublic void eat() {// 前置处理System.out.println("饲养员准备食物");animal.eat();// 后置处理System.out.println("饲养员收拾剩余食物");}
​@Overridepublic void sleep() {// 前置处理System.out.println("饲养员准备草席");animal.sleep();// 后置处理System.out.println("饲养员叫醒小动物");}
}

(4) 使用代理类
public class Test {public static void main(String[] args) {// 1.创建目标对象Animal animal = new Animal();// 2.创建代理对象(传入目标对象)AnimalProxy proxy = new AnimalProxy(animal);
​// 3.通过代理对象调用方法proxy.eat();System.out.println();proxy.sleep();}
}

运行结果:

image-20250926205040970

二. 动态代理

1. 概念

动态代理是一种 在运行时动态创建代理对象 的机制. 这种机制允许我们在不修改原始类代码的情况下, 对目标类的方法进行增强 (如添加日志, 事务控制, 权限校验等).

这种机制是代理模式的高级实现, 相比静态代理 (在编译期生成代理类), 动态代理更加灵活, 能避免大量重复代码.

例如: 如果我们要正在项目中添加一些新的功能. 但是在成熟的项目中, 不建议进行 "侵入式修改" (修改原本已经能正常运行的代码). 所以此时我们就要选择动态代理, 它能够无侵入式地给代码增加额外功能.

image-20250926171722965

2. JDK 动态代理

基于接口的代理.

实现步骤:

(1) 定义接口

定义一个接口, 该接口里是要代理的方法.

/*** IAnimal 接口* (这里写要被代理的方法)*/
public interface IAnimal {/*** 吃饭*/public abstract void eat();
​/*** 睡觉*/public abstract void sleep();
}

(2) 接口的实现类

BigStar 类 实现 Star 接口 (要被代理的对象类)

public class Animal implements IAnimal{
​@Overridepublic void eat() {System.out.println("吃吃吃");}
​@Overridepublic void sleep() {System.out.println("睡睡睡");}
}

(3) 生成代理对象

ProxyUtil 生成代理对象

java.lang.reflect.Proxy 类: 提供了为对象生成代理对象的方法.

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  • 参数一: 用于 指定用哪个类加载器 去加载生成的代理类.

  • 参数二: 指定接口数组. 这些接口用于指定要代理哪些方法.

  • 参数三: 用来指定生成的代理对象要干什么事情.

ProxyUtil 类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
/*** 代理工具类 ProxyUtil* 作用: 为对象创建代理*/
public class ProxyUtil {/*** 给Animal对象创建代理* @param animal 被代理的明星对象* @return 代理对象*/public static IAnimal createProxy(Animal animal) {return (IAnimal) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),   // 参数一: 用于指定用哪个类加载器去加载生成的代理类new Class[]{IAnimal.class},         // 参数二: 用于指定代理对象要实现哪些接口new InvocationHandler() {           // 参数三: 用于指定代理对象要干什么事情@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*参数1: 要代理的对象参数2: 要运行的方法参数3: 方法的参数*/// 前置处理if (("eat").equals(method.getName())) {System.out.println("饲养员准备食物");} else if ("sleep".equals(method.getName())) {System.out.println("饲养员准备草席");}
​// 调用目标类的原始方法 (通过代理调用父类方法)Object result = (method.invoke(animal, args));
​// 后置处理if (("eat").equals(method.getName())) {System.out.println("饲养员收拾剩余食物");} else if ("sleep".equals(method.getName())) {System.out.println("饲养员叫醒小动物");}
​return result;}});}
}

(4) 使用代理类

Test 测试类:

public class Test {public static void main(String[] args) {Animal animal = new Animal();
​// 1.获取代理对象IAnimal proxy = ProxyUtil.createProxy(animal);
​// 2.调用代理对象的方法proxy.eat();System.out.println();proxy.sleep();}
}

运行结果:

image-20250926205040970

3. CGLIB 动态代理

基于的代理.

实现步骤:

(1) 添加 CGLIB 依赖

在 pom.xml 文件中添加如下依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

(2) 定义目标类 (无需实现接口)
public class Animal {
​public void eat() {System.out.println("吃吃吃");}
​public void sleep() {System.out.println("睡睡睡");}
}

(3) 实现 MethodInterceptor 接口

(定义增强逻辑)

CGLIB 的核心是 MethodInterceptor 接口, 其 intercept() 方法类似于 JDK 的 invoke. 在代理方法被调用时执行, 参数包括:

  • obj: 代理对象 (子类实例)

  • method: 被调用的目标方法 (反射对象)

  • args: 方法参数

  • proxy: 方法代理对象 (用于调用父类的原始方法)

public class AnimalInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
​// 前置处理if (("eat").equals(method.getName())) {System.out.println("饲养员准备食物");} else if ("sleep".equals(method.getName())) {System.out.println("饲养员准备草席");}
​// 调用目标类的原始方法 (通过代理调用父类方法)Object result = proxy.invokeSuper(obj, args);
​// 后置处理if (("eat").equals(method.getName())) {System.out.println("饲养员收拾剩余食物");} else if ("sleep".equals(method.getName())) {System.out.println("饲养员叫醒小动物");}
​return result;}
}

(4) 使用代理类
import net.sf.cglib.proxy.Enhancer;
​
public class Test {public static void main(String[] args) {// 1. 创建目标对象Animal animal = new Animal();
​// 2. 创建 Enhancer (CGLIB的代理生成器)Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Animal.class); // 设置父类 (目标类)enhancer.setCallback(new AnimalInterceptor()); // 设置增强处理器
​// 3. 生成代理对象 (是Animal的子类)Animal proxy = (Animal) enhancer.create();
​// 4. 调用代理对象的方法proxy.eat();System.out.println();proxy.sleep();}
}

运行结果:

image-20250926205040970

http://www.dtcms.com/a/411211.html

相关文章:

  • 网站 繁体 js汽车cms
  • 怀化 网站建设东海县做网站广告
  • 嘉兴网页制作网站排名企业网站建设用什么语言
  • 《录井工程与管理》——第六章 钻井参数录井
  • 视觉/深度学习/机器学习相关面经总结(3)(持续更新)
  • Qt 自定义控件(继承 QWidget)面试核心指南
  • 网站建设友汇wordpress自动提取标签
  • 网络编程初识
  • Apring Ai 和Spring Ai Alibaba有什么区别
  • 网站开发的例子网站获取信息
  • 活到老学到老之Jenkins build triggers中的定时schedule规则细讲
  • 企业级 MySQL 8 全流程指南:源码编译安装、主从同步、延迟复制、半同步与 MHA 高可用搭建
  • 有服务器了怎么做网站三星网上商城分期
  • 交付场景下的 iOS 混淆实战,无源码部分源码如何做成品加固、供应链验证与交付治理
  • 中国菲律宾商会网站seo优化免费
  • CS课程项目设计18:基于Insightface人脸识别库的课堂签到系统
  • 收录网站的二级域名郑州又上热搜了
  • 济南企业型网站深圳定制网站制作
  • 【2025】Mixxx 2.5.1安装教程保姆级一键安装教程(附安装包)
  • 算法学习之 二分
  • Carboxyrhodamine 110 Alk,羧基罗丹明110-炔基在点击化学的应用
  • 日记 - 2025.9.26 读研日记(二)
  • 做网站数据库表设计优化大师win7官方免费下载
  • 中建建设银行网站电子邮箱
  • display ip routing-table 概念及题目
  • spring 第三级缓存singletonFactories的作用及@Async造成循环依赖报错原因分析
  • 什么是静态IP?静态IP和动态IP的对比
  • IP子网掩码的计算
  • 济南富新网站建设福州服务类网站建设
  • 网站设置快捷方式到桌面找大学生做家教的网站