Java代码审计学习笔记之JAVA基础系列(五、静态代理与动态代理)

0.什么是代理?

代理的概念其实非常类似于hook,正常hook的时候一般修改程序入口点,然后对输入进行一定的操作后调用被hook的函数。Java中的代理其实目的也是一样的,通过增加一个代理方法,在代理的方法中调用被代理的方法,从而对输入输出等进行一定的控制,流程如下图所示。代理主要分为静态代理动态代理两种。以下分别对其进行介绍。

1.静态代理

最容易想到的代理方式就是静态代理方式,静态代理及新建一个作为代理的类,在这个作为代理的类中去调用某个被代理的类。具体可参考如下代码:

1.声明一个接口

//HelloInterface.java
public interface HelloInterface {
    void sayHello(String name);
}

2.在某个类中实现这个接口

//Hello.java
public class Hello implements HelloInterface {
    @Override
    public void sayHello(String name){
        System.out.println("Hello " + name);
    }
}

3.写一个代理这个Hello类的Hello方法的代理类

//ProxyHello.java
public class ProxyHello implements HelloInterface {
    private String name;
    public ProxyHello(String name){
        this.name = name;
    }
    private Hello myHello = new Hello();//创建一个需要被代理的类
    @Override
    public void sayHello(String name) {
        System.out.println("Before invoke sayHello" );
        myHello.sayHello(this.name);//调用被代理类的sayHello方法
        System.out.println("After invoke sayHello");
    }
}

4.测试使用代理类

//testProxy.java
public class testProxy {
    public static void main(String args[]){
        ProxyHello test = new ProxyHello("Abbla");
        test.sayHello("Abcccbla");
    }
}

2.动态代理

使用上面的方法确实能在不修改某个类的代码时对其进行监控或结果的修改,但是每当需要对某个类进行代理的时候,就需要单独去写一个代理类,这显然很麻烦。因此就有这种动态代理的方法,其实简单来说动态代理方法就是把上面需要执行的Method被代理类等信息进行了变量化。通过传入变量的方式来进行代理,从而实现一个代理类可以适用于多个被代理类。具体实现如下:

1.声明一个接口

//HelloInterface.java
public interface HelloInterface {
    void sayHello(String name);
}

2.在某个类中实现这个接口

//Hello.java
public class Hello implements HelloInterface {
    @Override
    public void sayHello(String name){
        System.out.println("Hello " + name);
    }
}

3.编写一个动态代理方法

public class ProxyHello implements InvocationHandler {
    private Object object;
    public ProxyHello(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke "  + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

4.调用该方法

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

public class testProxy {
    public static void main(String args[]){
        Hello HelloInstance = new Hello();//创建一个被代理对象
        InvocationHandler myInvocationHandler = new ProxyHello(HelloInstance);//创建一个代理Handler
        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(HelloInstance.getClass().getClassLoader(), HelloInstance.getClass().getInterfaces(), myInvocationHandler);//实例化一个代理对象
        proxyHello.sayHello("hahahha!!");//通过代理对象调用sayHello方法
    }
}