首页 > 代码库 > Java代理笔记

Java代理笔记

代理顾名思义,就是一个中间层,当我们要使用某个方法时,不直接调用,而是告诉代理,让代理替我们去请求方法,并返回结果。在这个过程中,我们只知道代理执行并返回给了我们操作结果,至于它有没有其他操作并不知道,但这个也无关紧要,因为不管代理在请求实际方法之前和之后做了什么,对我们都不会产生任何影响。由于代理的这个特性,可以用来进行记录日志等操作。

代理分为静态代理动态代理

静态代理

静态代理需要我们在调用者和具体的执行者之间创建一个代理类,其实现需要被代理的接口并持有一个此接口,具体代码如下:

接口类(被代理):

public interface Hello {
    void say(String name);
}

代理类:

public class HelloProxy implements Hello {
?
    private Hello helloImpl;
?
    public HelloProxy() {
        this.helloImpl = new HelloImpl(); // HelloImpl为一个Hello接口的一个普通实现类
    }
?
    @Override
    public void say(String name) {
        System.out.println("before say");
        helloImpl.say(name);
        System.out.println("after say");
    }
}

使用的时候只需要new一个代理类赋值给接口即可:Hello hello = new HelloProxy(),之后的执行会由代理类去负责。但是这么做有一个问题就是对每个需要代理的类,都需要创建一个对应的代理类,即使代理类的逻辑都是相似的,动态代理就是解决这个问题的。

动态代理

动态代理相当于在调用者和代理类之间又增加了一个中间层,在这个中间层中完成代理类的逻辑,达到复用代码的效果。这个中间层需要实现InvocationHandler接口,并持有一个被代理的类,大致代码如下:

public class Myproxy implements InvocationHandler {
?
    private Object target; // 被代理的类
?
    public Myproxy(Object target) {
        this.target = target;
    }
?
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke"); // 执行代理的方法前进行的操作
        Object invoke = method.invoke(target, args); // 调用执行被代理的方法
        System.out.println("after invoke"); // 执行代理的方法后进行的操作
        return invoke; // 返回方法执行结果
    }
}

使用时,使用Proxy的静态方法获取代理类,将其强转为对应的接口,之后可以同静态代理类同样使用。

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

其中loader为类加载器,interfaces为要代理的接口,h为之前定义的实现InvocationHandler接口的类的实例。

这个方法会返回一个代理类,其实现的要代理的接口,并持有一个实现InvocationHandler接口的实例,代理类的代码大致如下:

public final class $Proxy0 extends Proxy
  implements Hello
{
?
  public $Proxy0(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }
?
  public final String say() {
    try
    {
      return ((String)this.h.invoke(this, m3, null));
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
?
}

如上代码我们可以将其强转为Hello接口,实际调用的时候会调用InvocationHandler实现类中的invoke方法,而其中就是我们实现的代理业务,当然,也包括实际的业务。

这样,对于有相同代理业务的类,我们只要实现InvocationHandler接口,在其中的invoke方法实现需要代理的业务,使用时只要使用Proxy.newProxyInstance静态方法,传入对应得参数即可得到需要的代理类,再将其强转赋值给需要的接口,即可正常使用。

 

Java代理笔记