Java中的代理
核心结论:代理类是Java中一种特殊类,它可替代目标类执行操作,能在不修改目标类代码的前提下,对其方法进行增强或控制访问,是实现AOP(面向切面编程)的重要技术基础。
为什么需要代理类?
在实际开发中,我们常需为目标类添加日志记录、权限校验、事务管理等通用功能。若直接修改目标类,会违反开闭原则(对扩展开放、对修改关闭)。代理类则可作为中间层,在调用目标方法前后嵌入额外逻辑,实现功能增强的同时,保持目标类的独立性。
代理类有哪些类型?
Java中的代理类主要分为两类,核心区别如下:
类型 实现方式 特点
静态代理 手动编写代理类,实现与目标类相同的接口 实现简单,但目标类增多时代理类会膨胀 适用场景 : 目标类少且接口稳定的场景
动态代理 运行时通过反射动态生成代理类 无需手动编写代理类,灵活性高 目标类多、 适用场景 : 需统一增强逻辑的场景
动态代理又可细分为JDK动态代理(基于接口)和CGLIB动态代理(基于继承,可代理无接口的类)。
一.静态代理
静态代理如何实现呢?
下面我们来看例子,‘假设我们要买一件大小为100码的衣服,这时候需要先有一个制衣服厂,但是我峨嵋你要怎末调用这个制衣方法呢,在Test里直接调用吗?
像这样?显然是不行的,因为用户怎末能直接创建一个源代码类型的对象呢?那样数据不就会用户更改了吗?所以不能调用 ,所以这时候就需要用到代理类,通过代理对象调用到核心对象的核心方法,从而实现购买
工厂(方法)----接口(告诉代理主要方法是啥,要调用哪个)-------代理(接受用户数据调用接口和方法)-------用户(需求购买)
下面来看代码
首先有一个制衣工厂
然后有一个代理对象,但是这时候问题又来了,通过这个代理对象我们怎末知道这个工厂是干啥的?换句话来说我们怎么知道里面的代码?怎末知道到底调用工厂里多个代码的哪一个?,所以这时候就要用接口来告诉代理商核心代码是啥,到底调用哪个方法 ******
接下来是接口:
最后就是用户调用代理类,代理类在调用接口里的方法:
总结:
核心结论:静态代理是Java代理模式的一种实现,指在编译期就已明确代理类的代码,且代理类与目标类实现相同接口,通过显式调用目标类方法,在其前后嵌入增强逻辑,从而实现对目标类的功能扩展。
静态代理的关键特征是什么?
- 编译期确定:代理类的源码需手动编写,与目标类一同编译为class文件,运行前代理类就已存在。
- 接口依赖:代理类和目标类必须实现同一个业务接口,确保代理类可替代目标类对外提供服务(遵循里氏替换原则)。
- 显式关联:代理类中通常会持有目标类的实例,在代理方法中直接调用目标类的对应方法。
静态代理的实现逻辑是怎样的?
1. 定义一个接口(如 UserService ),声明目标类和代理类共同的方法(如 saveUser() )。
2. 目标类(如 UserServiceImpl )实现该接口,编写核心业务逻辑。
3. 代理类(如 UserServiceProxy )同样实现接口,在其方法中:
- 调用目标类的对应方法(如 userService.saveUser() )。
- 在调用前后添加增强逻辑(如日志打印、参数校验)
二.动态代理
静态代理会有很多弊端:
- 代码冗余:每增加一个目标类,若需代理则需新增一个代理类,导致类数量激增。
- 维护成本高:当接口方法修改时,目标类和所有代理类都需同步修改,违背开闭原则。
即当工厂太多时,只能自己手写增加,太过繁琐,所以就有了动态代理
所谓动态代理就是让代理类根据工厂数目生成代理对象,,从而达到一个代理一个工厂
下面我们来看代码:
区别就是代理类动态代理类是有一个全局变量target,接受Object数据,静态代理则是直接写代理工厂的名称
那麽具体过程有啥区别呢?
main方法入栈之后,会获取这个代理类里面的targrt,然后这个target会根据接口来调用工厂里的方法这就是动态代理
工厂:
package com.qcby;public class ClothesFactory implements makeClothes{public void makeClothes(Integer size){System.out.println("为您定制了一款大小为"+size+"的衣服");}}
接口:
package com.qcby;public interface makeClothes {public void makeClothes(Integer size);
}
代理类:
package com.qcby;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** InvocationHandler*/
public class 动态代理类 implements InvocationHandler {//创建目标对象 ----------》没有直接指明我到底代理的谁?private Object target;public 动态代理类(Object target) {this.target = target;}/*** 获取目标对象的接口:知道目标类的核心方法是谁了。* @return*/public Object getProxy(){return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}/*** 这个方法是jdk给咱们提供的,帮助咱们去调用目标对象方法* @param proxy* @param method --------》目标对象的核心方法* @param args ----------->目标对象核心方法参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {FrontService();method.invoke(target,args);endService();return null;}//前置服务public void FrontService() {System.out.println("根据您的需求进行市场调研");}//前置服务public void endService() {System.out.println("为您提供一条龙的包办服务");}}
用户:
package com.qcby;public class XiaoHong {public static void main(String[] args) {//让代理对象引用目标对象动态代理类 d = new 动态代理类(new ClothesFactory());//2.获取目标对象的接口makeClothes makeClothes = (com.qcby.makeClothes) d.getProxy();makeClothes.makeClothes(100);动态代理类 c = new 动态代理类(new ShootFactory());}
}
总结:
核心结论:动态代理是Java中在运行时动态生成代理类的技术,无需手动编写代理代码,能为目标类动态添加增强逻辑,是实现灵活解耦和批量功能增强的关键手段。
动态代理的核心特征是什么?
- 动态生成:代理类在程序运行时由JVM通过反射机制动态创建,而非编译期预先定义。
- 接口依赖(JDK动态代理):默认要求目标类实现接口,代理类会动态实现相同接口(CGLIB动态代理可突破此限制,基于继承实现)。
- 统一增强:可通过一个代理逻辑处理多个目标类,避免静态代理的类膨胀问题。
动态代理的核心价值是什么?
1. 减少代码冗余:无需为每个目标类编写代理类,统一通过拦截器实现增强逻辑。
2. 提高灵活性:运行时可动态指定目标类和增强行为,适应多变的业务需求。
3. 支撑框架底层:是Spring AOP、MyBatis插件等框架实现的核心技术,实现事务管理、日志拦截等切面功能。
总结:
动态代理通过运行时动态生成代理类,解决了静态代理的扩展性问题,既能在不修改目标类的前提下增强功能,又能适应大量目标类的统一处理场景,是Java中实现面向切面编程和框架灵活性的核心技术之一。