java反序列化学习—动态代理
1. Java 代理模式
理解代理模式,首先要明确“代理”的含义。下面这张图中的中介,正代表着软件设计中的代理角色。它代理的对象(称为被代理类或委托类)就像是房东,只需专注于核心业务逻辑(比如管理房屋的基本信息),而将衍生或辅助的业务逻辑(例如如何租赁、筛选租客、处理合同等)委托给代理(即中介)来完成。

2. 静态代理
以租客找中介向房东租房子为例,想要实现租客找中介,中介转租房东房源,在 Java 中就需要4个文件,分别是房源、房东、中介、租客,其中房源应该是接口,其余三项为类。
HousingResource.java:这是一个接口,可以抽象的理解为房源,作为房源,它有一个方法rent()为租房
public interface HousingResource {
public void rent();
}
Landlord.java这个类就是房东,作为房东,他需要实现rent.java这一个接口,并且要实现接口的rent()方法。
public class Landlord implements HousingResource{
@Override
public void rent() {
System.out.println("房东出租房了");
}
}
IntermediaryAgent.java:这个类是中介,也就是代理,他需要有房东的房源,然而我们通常不会继承房东,而会将房东作为一个私有的属性landlord,我们通landlord.rent()`来实现租房的方法.
// 中介
// 中介
public class IntermediaryAgent {
private Landlord landlord;
public IntermediaryAgent(){}
public IntermediaryAgent(Landlord landlord){
this.landlord = landlord;
}
public void rent(){
System.out.println("中介转租");
landlord.rent();
}
}
Tenant.java: 这个类是租客去找中介看房。
public class Tenant {
public static void main(String[] args) {
Landlord landlord = new Landlord();
IntermediaryAgent proxy = new IntermediaryAgent(landlord);
proxy.rent();
}
}
至此静态代理租房就完成了。

但是,我们中介不可能只有这一个行为,有一些行为是中介可以做的,而房东不能做的,比如看房,收中介费等等。所以我们要在 Proxy.java当中实现这些功能。
// 中介
public class IntermediaryAgent {
private Landlord landlord;
public IntermediaryAgent(){}
public IntermediaryAgent(Landlord landlord){
this.landlord = landlord;
}
public void rent(){
System.out.println("中介转租");
landlord.rent();
fare();
contract();
}
// 看房
public void seeHouse(){
System.out.println("中介带你看房");
}
// 收中介费
public void fare(){
System.out.println("收中介费");
}
// 签租赁合同
public void contract(){
System.out.println("签租赁合同");
}
}
但我们实际项目中被代理类不可能只存在一个功能,那这样的话,代理类也要实现相关功能,这样的话代码量就很大,下面通过一个简单实现业务中CRUD的日志功能来学习。
UserService.java,这是一个接口,我们定义四个抽象方法。
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
我们需要一个真实对象来完成这些增删改查操作。
UserServiceImpl.java实现这四个功能。
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
}
需求来了,现在我们需要增加一个日志功能,怎么实现!
增加一个代理类来处理日志。
UserServiceProxy.java处理日志
// 代理
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
// 增加日志方法
public void log(String msg){
System.out.println("[Debug]使用了 " + msg +"方法");
}
}
再写一个启动类看看效果
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
可以发现当业务功能多的时候,代码量会很大,不方便,且每多一个房东便要多一个中介,这时便需要一个简便的代理方法,这就是动态代理。
3. 动态代理
动态代理的角色和静态代理的一样。需要一个实体类,一个代理类,一个启动器。
JDK的动态代理需要了解两个类核心 : InvocationHandler 调用处理程序类和 Proxy 代理类
InvocationHandler是由代理实例的调用处理程序实现的接口
每个代理实例都有一个关联的调用处理程序。

当在代理实例上调用方法的时候,方法调用将被分派到其调用处理程序的invoke()方法。
参数:
proxy– 调用该方法的代理实例
method-所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
args-包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean。
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
动态代理类 (以下简称为代理类 )是一个实现在类创建时在运行时指定的接口列表的类,具有如下所述的行为。 代理接口是由代理类实现的接口。 代理实例是代理类的一个实例。

返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
参数
loader– 类加载器来定义代理类
interfaces– 代理类实现的接口列表
h– 调度方法调用的调用处理函数
动态代理的代码实现
要写动态代理的代码,需要抓牢两个要点
①:我们代理的是接口,而不是单个用户。
②:代理类是动态生成的,而非静态定死。
首先是我们的接口类
interface Hello {
String sayHello(String name);
}
接口实现类
public class HelloImpl implements Hello{
@Override
public String sayHello(String name) {
System.out.println("[真实对象] 方法执行");
return "Hello, " + name;
}
}
动态代理的实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class LogHandler implements InvocationHandler {
private final Object target;
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("[代理] 调用方法: " + method.getName() +
" 参数: " + Arrays.toString(args));
// 调用真实对象的方法(关键步骤)
Object result = method.invoke(target, args);
// 后置增强
System.out.println("[代理] 返回结果: " + result);
return result;
}
}
最后编写我们的启动类>
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Hello real = new HelloImpl();
InvocationHandler handler = new LogHandler(real);
Hello proxy = (Hello) Proxy.newProxyInstance(real.getClass().getClassLoader(), new Class[]{Hello.class},handler);
System.out.println("[客户端] 调用代理方法");
String result = proxy.sayHello("World");
System.out.println("[客户端] 最终结果: " + result);
}
}
来看看效果


浙公网安备 33010602011771号