java动态代理、Proxy与InvocationHandler

文章来源:

https://www.cnblogs.com/LCcnblogs/p/6823982.html

Github代码地址:

https://github.com/DemoTransfer/demotransfer/tree/master/pattern/proxy

下面的内容关于代理讲解的不是很深,但是很容易理解,很适合初次接触代理的开发同事。

一、代理的基本构成

抽象角色:

声明真实对象和代理对象的共同接口,这样可在任何使用真实对象的地方都可以使用代理对象。

代理角色:

代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象提供一个与真实对象相同的接口,以便可以在任何时候替代真实对象。代理对象通常在客户端调用传递给真实对象之前或之后,执行某个操作,而不是单纯地将调用传递给真实对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:

即为代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象。

下图有三种角色:Subject抽象角色、RealSubject真实角色、Proxy代理角色。其中:Subject角色负责定义RealSubject和Proxy角色应该实现的接口;RealSubject角色用来真正完成业务服务功能;Proxy角色负责将自身的request请求,调用RealSubject对应的request功能来实现业务功能,自己不真正做业务。

![这里写图片描述](https://img-blog.csdn.net/20180406144443994?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM0MTI3NzI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

二、静态代理

interface Subject//抽象角色
{  
    public void doSomething();  
}
class RealSubject implements Subject//真实角色
{  
    public void doSomething()  
  {  
    System.out.println( "call doSomething()" );  
  }  
}
class SubjectProxy implements Subject//代理角色
{
  //代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
  Subject subimpl = new RealSubject();
  public void doSomething()
  {
     System.out.println("before"); //调用目标对象之前可以做相关操作
     subimpl.doSomething();
     System.out.println("after");//调用目标对象之后可以做相关操作
  }
}
 
public class Test
{
    public static void main(String[] args) throws Exception
    {
        Subject sub = new SubjectProxy();
        sub.doSomething();
    }
}

可以看到,SubjectProxy实现了Subject接口(和RealSubject实现相同接口),并持有的是Subject接口类型的引用。这样调用的依然是doSomething方法,只是实例化对象的过程改变了,结果来看,代理类SubjectProxy可以自动为我们加上了before和after等我们需要的动作。

如果将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,对导致代理类的代码变得臃肿;另一方面,当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。

三、JDK动态代理

interface Subject  
{  
    public void doSomething();  
}
class RealSubject implements Subject  
{  
    public void doSomething()  
  {  
     System.out.println( "call doSomething()" );  
  }  
}
class ProxyHandler implements InvocationHandler
{
    private Object tar;
    //绑定委托对象,并返回代理类
    public Object bind(Object tar)
    {
        this.tar = tar;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
                                      tar.getClass().getInterfaces(),
                                      this);
    }   
    public Object invoke(Object proxy , Method method , Object[] args)throws Throwable//不依赖具体接口实现
    {
        Object result = null;//被代理的类型为Object基类
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        result = method.invoke(tar,args);
        //在调用具体函数方法后,执行功能处理
        return result;
    }
}
public class Test
{
    public static void main(String args[])
    {
           ProxyHandler proxy = new ProxyHandler();
           //绑定该类实现的所有接口
           Subject sub = (Subject) proxy.bind(new RealSubject());
           sub.doSomething();
    }
}

在调用过程中使用了通用的代理类包装了RealSubject实例,然后调用了Jdk的代理工厂方法实例化了一个具体的代理类。最后调用代理的doSomething方法,还有附加的before、after方法可以被任意复用(只要我们在调用代码处使用这个通用代理类去包装任意想要需要包装的被代理类即可)。当接口改变的时候,虽然被代理类需要改变,但是我们的代理类却不用改变了。这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显示的创建一个实现具体接口的代理类。

四、接口InvocationHandler

InvocationHandler 是代理实例的调用处理程序 实现的接口。 每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

/**
 在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。 
 */
Object invoke(Object proxy, Method method, Object[] args) throws Throwable

参数:

  1. proxy - 在其上调用方法的代理实例

  2. method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

  3. args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或java.lang.Boolean)的实例中。

返回:

  • 从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出ClassCastException。

抛出:

  • Throwable - 从代理实例上的方法调用抛出的异常。该异常的类型必须可以分配到在接口方法的 throws子句中声明的任一异常类型或未经检查的异常类型 java.lang.RuntimeException 或java.lang.Error。如果此方法抛出经过检查的异常,该异常不可分配到在接口方法的 throws子句中声明的任一异常类型,代理实例的方法调用将抛出包含此方法曾抛出的异常的UndeclaredThrowableException。

你可能感兴趣的:(设计模式相关技术)