参考资料:白日梦组长
什么是代理?
定义:为其他对象提供一种代理以控制对这个对象的访问

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
引出第一个代理的主要意义:
代理模式使得客户端代码与实际对象的实现分离。通
过代理,可以将一些额外的功能(如日志记录、权限控制、性能监控等)插入到真实对象的操作中,而不需要改变实际对象的代码。这种方式有效地降低了代码的耦合度,提高了系统的可扩展性和可维护性。
静态代理
接口 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
评论(已关闭)
评论已关闭