前言
看了很多前辈的文章,都提到了Java的一大核心机制: 动态代理机制(Dynamic Proxy), 这一知识点我断断续续看了有好几天,不复杂但有点绕,所以一直没有写出这篇博文,好在查询了众多资料,现在有了一些自己的理解。
这一章将探究JAVA静态和动态代理机制 - 有助于我们理解YSoSerial的playload实现机制。
Java代理机制
什么是代理机制
Proxy Design实际上是一种软件设计模式,
A proxy receives client requests, does some work (access control, caching, etc.) and then passes the request to a service object.
因为安全问题,client不允许直接access服务端上的某个服务,需要一个Proxy class先处理client的请求,通过Proxy class来访问这个服务,再返回给Client。
而Proxy Class就是代理, 委托Proxy Class帮他和客户建立连接的服务就是Delegate Class - 委托类(被代理)。
通常Proxy和Delegate委托类有相同的方法,且Proxy拥有委托类的reference,可以调用其方法。在调用其方法的时候,Proxy可以在其基础上添加或者修改功能,这样就不需要修改到委托类,修改代理类本身就可以了。
一个形象的例子:A是房东,他需要出租自己的房子,他会委托代理B(中介)把房子挂在网上,当客户C需要租房时,C会直接和代理B进行交流而不是直接和房东A交流。
所以我们可以得出使用代理模式的好处:
- Proxies 让我们可以在不改变委托类的情况下,自定义修改委托类方法代码执行前和执行后的behaviour
- Proxy pattern是安全的。一个远程的代理可以提供一个proxy stub给客户端, 然后在Server端call the implementation(此处是不是很像我们在Java反序列化漏洞之JAVA RMI原理、流程(2)中所提到的JAVA RMI呢?)
静态代理
静态代理就是手动编写代理类。
委托类和代理类要实现相同的接口
来看看静态代理是如何实现的:
1 | public interface TestDelegate { |
1 | public class TestImp implements TestDelegate { |
代理类handle一个委托类的object:
1 | public class TestProxy implements TestDelegate{ |
Client尝试访问sayHello():
1 | public class Test { |
静态代理的缺陷:
程序员要手动为每一个委托类编写一个对应的代理类,如果当前系统有上百千个类,工作量就太大了。而动态代理可以帮助我们解决这个问题。
动态代理
动态代理,简单的说就是用一个代理类帮我们动态生成了不同类的代理,我们不需要手动针对每个委托类编写一个队形的代理类。
InvocationHandler接口:负责提供调用代理操作。
是由代理对象调用处理器实现的接口,定义了一个invoke()方法,每个代理对象都有一个关联的接口。当代理对象上调用方法时,该方法会被自动转发到InvocationHandler.invoke()方法来进行调用。
看代码
1 | public interface TestDelegate { |
1 | public class TestImp implements TestDelegate { |
1 | package dynamic; |
1 | package dynamic; |
由此可见,动态代理的作用:
动态代理只需要实现一个代理类,而静态代理需要实现多个代理类
解耦,通过参数就可以判断真实类,不需要实现实例化,更加灵活多变
Reference
Java 动态代理作用是什么? - bravo1988的回答 - 知乎
Java 动态代理作用是什么? - ZeaTalk的回答 - 知乎