boxmoe_header_banner_img

Hello! 欢迎来到zz的小站!

加载中

文章导读

java 代理机制


avatar
zzdzz 2025年10月11日 194

参考资料:白日梦组长

什么是代理?

定义:为其他对象提供一种代理以控制对这个对象的访问

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

引出第一个代理的主要意义:

代理模式使得客户端代码与实际对象的实现分离。通

过代理,可以将一些额外的功能(如日志记录、权限控制、性能监控等)插入到真实对象的操作中,而不需要改变实际对象的代码。这种方式有效地降低了代码的耦合度,提高了系统的可扩展性和可维护性。

静态代理

接口 IUser​

package daili;

public interface IUser {
    void show();
}

一个简单的接口,声明了一个 show()​ 方法,所有实现这个接口的类都必须提供该方法的具体实现。

实现类 UserImpl​

package daili;

public class UserImpl implements IUser{
    public UserImpl() {
    }

    @Override
    public void show() {
        System.out.println("展示");
    }
}

​UserProxy​ 是代理类,它实现了 IUser​ 接口,并持有一个 IUser​ 类型的对象(真实对象)。show()​ 方法在执行时不仅调用了真实对象的 show()​ 方法,还在其后添加了一些额外的操作——打印“调用了show”。

代理类 UserProxy​

package daili;

public class UserProxy implements IUser {
    IUser user;

    public UserProxy() {
    }

    public UserProxy(IUser user) {
        this.user = user;
    }

    @Override
    public void show() {
        user.show();  // 调用真实对象的show方法
        System.out.println("调用了show");  // 增加额外的行为
    }
}

​UserProxy​ 是代理类,它实现了 IUser​ 接口,并持有一个 IUser​ 类型的对象(真实对象)。show()​ 方法在执行时不仅调用了真实对象的 show()​ 方法,还在其后添加了一些额外的操作——打印“调用了show”。

测试类 ProxyTest​

package daili;

public class ProxyTest {
    public static void main(String[] args) {
        IUser user = new UserImpl();
//        user.show();

        // 静态代理
        IUser userProxy = new UserProxy(user);
        userProxy.show();  // 代理调用
    }
}

在 ProxyTest​ 中,创建了一个 UserImpl​ 的实例作为真实对象,并通过 UserProxy​ 代理对象来间接调用 show()​ 方法。最终输出的内容是:

展示
调用了show

此时,接口只有一个方法,因此也只需要重写一次,但是当有很多方法需要重写时,静态代理就显得累赘,我们想要简化,就需要知道代码调用了哪个方法,从而反射实现增加功能,但是我们无法得知获取调用了哪个方法,从而引出了动态代理的技术。

动态代理

如果你想让代理更具灵活性,可以使用 动态代理,它允许在运行时动态地为任何对象创建代理,而不需要显式地编写每个代理类。

重点方法:Proxy.newProxyInstance()​ 来源:java.lang.reflect.Proxy​

前俩参数比较好填,模版化

Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),   );

我们需要写一个类继承InvocationHandler​

需要重写方法invoke​

可以发现他自己能够获取到method,只需要method.invoke()即可

UserInvocationHandler

package daili;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserInvocationHandler implements InvocationHandler {
    IUser user;
    public UserInvocationHandler(){}
    public UserInvocationHandler(IUser user) {
        this.user = user;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用了"+method.getName());
        method.invoke(user, args);
        return null;
    }
}

测试类ProxyTest

package daili;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        IUser user = new UserImpl();
//        user.show();

        //静态代理
//        IUser userProxy = new UserProxy(user);
//        userProxy.show();

        //动态代理
        InvocationHandler userInvocationHandler = new UserInvocationHandler(user);
        IUser userproxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),userInvocationHandler);
        userproxy.show();
    }
}

动态代理对于java反序列化的意义

找到一个漏洞利用点,在 B.f (B类的f方法)

找到入口 A[O] (A类接受参数O类)

=> O.abc(希望直接调用O.f,但是他调用O.abc方法)

此时,当O为一个动态代理类时,O.abc一定会调用O.invoke

O[O2].invoke => O2.f

传入O2为B

=> B.f

类似于 反序列化自动执行 readObject

有函数调用自动执行 invoke



评论(已关闭)

评论已关闭