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();} }
运行结果:
二. 动态代理
1. 概念
动态代理是一种 在运行时动态创建代理对象 的机制. 这种机制允许我们在不修改原始类代码的情况下, 对目标类的方法进行增强 (如添加日志, 事务控制, 权限校验等).
这种机制是代理模式的高级实现, 相比静态代理 (在编译期生成代理类), 动态代理更加灵活, 能避免大量重复代码.
例如: 如果我们要正在项目中添加一些新的功能. 但是在成熟的项目中, 不建议进行 "侵入式修改" (修改原本已经能正常运行的代码). 所以此时我们就要选择动态代理, 它能够无侵入式地给代码增加额外功能.
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();} }
运行结果:
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();} }
运行结果: