JDK动态代理
讲一下静态代理
User.java
public interface User
{
void show();
}
UserImpl.java
public class UserImpl implements User
{
public UserImpl(){}
public void show(){
System.out.println("展示");
}
}
Test.java
public class Test
{
public static void main(String[] args)
{
User user = new UserImpl();
user.show();
}
}
跑一下
写一个
UserProxy.java 模拟代理
public class UserProxy implements User
{
User user;
public UserProxy(){
}
public UserProxy(User a){
user = a;
}
public void show(){
user.show();
System.out.println("由代理完成");
}
}
test.java
public class Test
{
public static void main(String[] args)
{
User user = new UserImpl();
//user.show();
UserProxy userProxy = new UserProxy(user);
userProxy.show();
}
}
这是静态的代理
如果接口中需要的实现的函数很多的话,那么代码量要变大
接口要实现的变多
这个就要变多
那么为了节省代码量可以使用动态代理技术
试想:如果代理类只用一个方法就能够实现接口中所有的函数,那它需要什么输入?
- 需要代理的类的名称(接口类名称)
- 需要执行的操作(接口类要实现的函数)
- Classloader (加载以上)
user.java
public interface User
{
void show();
void update();
void delete();
}
UserImpl.java
public class UserImpl implements User
{
public UserImpl(){}
public void show(){
System.out.println("展示");
}
public void update(){
System.out.println("更新");
}
public void delete(){
System.out.println("删除");
}
}
UserProxy.java
public class UserProxy implements User
{
User user;
public UserProxy(){
}
public UserProxy(User a){
user = a;
}
public void show(){
user.show();
System.out.println("由代理完成");
}
public void update(){
user.update();
System.out.println("由代理完成");
}
public void delete(){
user.delete();
System.out.println("由代理完成");
}
}
可以自己test.java试试
现在介绍动态代理
Proxy.newProxyInstance()
前两个输入就是前面提到的设想中的输入,后面那个比较重要
InvocationHandler
发现是个接口,需要实现它的invoke函数
于是新建一个类UserProxyPlus去继承该方法并实现
其实它是用来加载并执行一个类的
原本我们用反射要执行一个函数需要
有了它,如今只需
它的method和args已经帮你搞定了,构造函数那些可以不用自己写
唯一缺的参数是需要加载和执行对象,所以我们把它传进来
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class UserProxyPlus implements InvocationHandler
{
User o;
public UserProxyPlus(User user)
{
o = user;
}
...
}
完整代码如下
UserProxyPlus.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class UserProxyPlus implements InvocationHandler
{
User o;
public UserProxyPlus(User user)
{
o = user;
}
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException
{
method.invoke(o,args);
return null;
}
}
Test.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test
{
public static void main(String[] args)
{
User user = new UserImpl();
//user.show();
//UserProxy userProxy = new UserProxy(user);
UserProxyPlus userProxyPlus = new UserProxyPlus(user);
User userproxyPlus = (User) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userProxyPlus);
userproxyPlus.show();
}
}
由于invoke方法是当有函数执行的时候会自动调用
就像上面例子调用userproxyPlus.show();会自动调用userproxyPlus里面的invoke方法
所以invoke方法里面如果也存在同名同类型的函数,也会触发反序列化的gadget