当前位置: 移动技术网 > IT编程>开发语言>Java > Java中的代理模式详解及实例代码

Java中的代理模式详解及实例代码

2019年07月22日  | 移动技术网IT编程  | 我要评论

青岛自助游,黄网站网址能进的2015 请给几个,智能机器人概念股

java 代理模式详解

前言:

在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能。

静态代理

所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则是在程序运行时自动生成代理类。

描述起来太过抽象,看一下代码就明白是怎么回事了

main

public class main {

  public static void main(string[] args) {
    water water = new water();
    waterproxy waterproxy = new waterproxy(water);
    waterproxy.drink();
  }

}

接口

//代理类与被代理类共同实现的接口
public interface drink {
  void drink();
}

被代理类

//被代理的类
public class water implements drink {

  @override
  public void drink() {
    system.out.println("drink water");
  }

}

代理类

//代理类
//与被代理类实现同一个接口
public class drinkproxy implements drink {
  
  private drink drinkimpl;
  
  //通过构造函数传入water对象
  public drinkproxy(drink drinkimpl) {
    this.drinkimpl = drinkimpl;
  }
  
  @override
  public void drink() {
    //在执行被代理对象的方法前做一些事情
    system.out.println("before drink");
    //执行被代理对象的方法
    drinkimpl.drink();
    //在执行被代理对象的方法后做一些事
    system.out.println("after drink");
  }

}

执行结果

before drink
drink water
after drink

动态代理

有时候我们只想改变代理类所代理的类,但是代理对象执行实际对象的方法前后所做的事情是一样的,正所谓铁打的代理类,流水的被代理类。而采用静态代理就只能代理实现了同一接口的类,如果要代理任意类则必须写很多重复的代理类。此时我们可以采用动态代理,java已经为实现动态代理提供了一套比较方便的工具。

java.lang.reflect.proxy类中可以动态生成代理对象的方法

/**
   *返回实现了指定接口的对象,调用代理对象的方法会调用 
   *invocationhandler的invoke方法
   *
   * @param  loader 获取代理类所使用的类加载器
   * @param  interfaces 代理类所要实现的接口
   * @param  h 实现了invocationhandler接口的对象
   * @return 代理对象
   */
public static object newproxyinstance(classloader loader,class<?>[] interfaces, invocationhandler h)

invocationhandler接口

/**
 *每个代理类都有一个关联的invocationhandler
 *当代理对象执行一个方法的时候会直接执行invoke方法
 */
public interface invocationhandler {

  /**
   * @param  调用该方法的代理对象
   * @param  method 代理对象所调用的方法
   * @param  args 调用的方法的参数
   * @return 调用的方法的返回值
   */
  public object invoke(object proxy, method method, object[] args)
}


描述总是比较抽象,还是看实际例子比较好理解

例子

invocationhandler接口的实现类

public class commoninvocationhandler implements invocationhandler {
  
  //被代理的对象
  private object proxied;
  
  public commoninvocationhandler(object proxied) {
    this.proxied = proxied;
  }
  
  @override
  public object invoke(object proxy, method method, object[] args) throws throwable {
    //在调用被代理对象的方法前做一些事情
    system.out.println("before doing something");
    //调用被代理对象的方法
    object result = method.invoke(proxied, args);
    //在调用被代理对象的方法后做一些事情
    system.out.println("after doing something");;
    return result;
  }

}

main

public class main {

  public static void main(string[] args) {
    //被代理的对象
    water water = new water();
    //动态获取代理对象
    drink waterproxy = 
        (drink) proxy.newproxyinstance(water.getclass().getclassloader(),
            water.getclass().getinterfaces(), 
            new commoninvocationhandler(water));
    //通过代理对象调用方法
    waterproxy.drink();
  }

}

输出结果

before doing something
drink water
after doing something

也可以不要具体的被代理对象,但是必须有相应的接口(没有实现接口的类可以使用cglib实现动态代理)才可以动态获取代理对象。像最近比较火的retrofit就直接通过声明好的接口使用动态代理进行网络请求。

例子

简单的模拟一下retrofit

post注解

//post请求注解
@target(elementtype.method)
@retention(retentionpolicy.runtime)
public @interface post {
 string value() default "";
}

query注解

//post请求注解
@target(elementtype.method)
@retention(retentionpolicy.runtime)
public @interface post {
 string value() default "";
}

service接口

public interface service {
  //用post注解声明请求的方式和相对路径
  @post("/login")
  //@query注解声明请求的参数名
  void login(@query("username")string username, 
      @query("password")string password);
}

main

public class main {

  public static void main(string[] args) {
    // 动态获取service接口的代理
    service service = (service) proxy.newproxyinstance(service.class.getclassloader(),
        new class[] { service.class }, new invocationhandler() {

          @override
          public object invoke(object proxy, method method, object[] args) throws throwable {
            // 通过注解获取请求的相对路径
            string retativepath = ((post) method.getannotations()[0]).value();
            system.out.println("relative path: " + retativepath);
            // 获取参数的注解
            annotation[][] parameterannotations = method.getparameterannotations();
            // 通过参数的注解获取请求参数
            for (int i = 0; i < parameterannotations.length; i++) {
              if (parameterannotations[i].length != 0) {
                for (int j = 0; j < parameterannotations[i].length; j++) {
                  query query = (query) parameterannotations[i][j];
                  system.out.println(query.value() + ": " + args[i].tostring());
                }
              }
            }
            return null;
          }
        });
    // 调用代理对象的方法
    service.login("hello", "world");
  }

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网