Java 中的代理模式

目录

[Java 的静态代理与动态代理](#Java 的静态代理与动态代理)

[一. 静态代理](#一. 静态代理)

[1. 概念](#1. 概念)

[2. 实现](#2. 实现)

[(1) 定义目标接口](#(1) 定义目标接口)

[(2) 定义目标类](#(2) 定义目标类)

[(3) 定义代理类](#(3) 定义代理类)

[(4) 使用代理类](#(4) 使用代理类)

[二. 动态代理](#二. 动态代理)

[1. 概念](#1. 概念)

[2. JDK 动态代理](#2. JDK 动态代理)

[(1) 定义接口](#(1) 定义接口)

[(2) 接口的实现类](#(2) 接口的实现类)

[(3) 生成代理对象](#(3) 生成代理对象)

[(4) 使用代理类](#(4) 使用代理类)

[3. CGLIB 动态代理](#3. CGLIB 动态代理)

[(1) 添加 CGLIB 依赖](#(1) 添加 CGLIB 依赖)

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

[(3) 实现 MethodInterceptor 接口](#(3) 实现 MethodInterceptor 接口)

[(4) 使用代理类](#(4) 使用代理类)


Java 的静态代理与动态代理

一. 静态代理

1. 概念

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

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

静态代理的核心是:

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

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

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

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

2. 实现
(1) 定义目标接口
复制代码
/**
 * IAnimal 接口
 * (这里写要被代理的方法)
 */
public interface IAnimal {
    /**
     * 吃饭
     */
    public abstract void eat();
​
    /**
     * 睡觉
     */
    public abstract void sleep();
}
(2) 定义目标类
复制代码
/**
 * 目标类 Animal
 */
public class Animal implements IAnimal{
​
    @Override
    public void eat() {
        System.out.println("吃吃吃");
    }
​
    @Override
    public void sleep() {
        System.out.println("睡睡睡");
    }
}
(3) 定义代理类
复制代码
/**
 * 代理类 AnimalProxy
 */
public class AnimalProxy implements IAnimal {
​
    private final Animal animal;
​
    public AnimalProxy(Animal animal) {
        this.animal = animal;
    }
    @Override
    public void eat() {
        // 前置处理
        System.out.println("饲养员准备食物");
        animal.eat();
        // 后置处理
        System.out.println("饲养员收拾剩余食物");
    }
​
    @Override
    public 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();
    }
}

运行结果:

二. 动态代理

1. 概念

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

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

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

2. JDK 动态代理

基于接口的代理.

实现步骤:

(1) 定义接口

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

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

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

复制代码
public class Animal implements IAnimal{
​
    @Override
    public void eat() {
        System.out.println("吃吃吃");
    }
​
    @Override
    public 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() {           // 参数三: 用于指定代理对象要干什么事情
                    @Override
                    public 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();
    }
}

运行结果:

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 {
    @Override
    public 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();
    }
}

运行结果:

相关推荐
风语者6662 小时前
perl踩坑系列=====正则表达式捕获
开发语言·perl
我科绝伦(Huanhuan Zhou)2 小时前
银河麒麟V10编译perl-5.42.0,并设置环境变量
开发语言·perl
舒克起飞了2 小时前
设计模式——单例模式
java·单例模式·设计模式
大飞pkz2 小时前
【设计模式】享元模式
开发语言·设计模式·c#·享元模式
Java&Develop3 小时前
GitLab-如何基于现有项目仓库,复制出新的项目仓库
java
茉莉玫瑰花茶3 小时前
C++扩展 --- 并发支持库(补充3)
开发语言·c++
一只乔哇噻3 小时前
java后端工程师进修ing(研一版‖day49)
java·开发语言
稻草猫.3 小时前
Java线程安全:volatile与wait/notify详解
java·后端·idea
枫叶丹43 小时前
【Qt开发】输入类控件(二)-> QTextEdit
开发语言·qt