详解设计模式中的proxy代理模式及在Java程序中的实现

一、代理模式定义

给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。
著名的代理模式的例子就是引用计数(reference counting): 当需要一个复杂对象的多份副本时, 代理模式可以结合享元模式以减少存储器的用量。典型做法是创建一个复杂对象以及多个代理者, 每个代理者会引用到原本的对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时, 复杂对象会被移除。

要理解代理模式很简单,其实生活当中就存在代理模式:
我们购买火车票可以去火车站买,但是也可以去火车票代售处买,此处的火车票代售处就是火车站购票的代理,即我们在代售点发出买票请求,代售点会把请求发给火车站,火车站把购买成功响应发给代售点,代售点再告诉你。
但是代售点只能买票,不能退票,而火车站能买票也能退票,因此代理对象支持的操作可能和委托对象的操作有所不同。

再举一个写程序会碰到的一个例子:
如果现在有一个已有项目(你没有源代码,只能调用它)能够调用 int compute(String exp1) 实现对于后缀表达式的计算,你想使用这个项目实现对于中缀表达式的计算,那么你可以写一个代理类,并且其中也定义一个compute(String exp2),这个exp2参数是中缀表达式,因此你需要在调用已有项目的 compute() 之前将中缀表达式转换成后缀表达式(Preprocess),再调用已有项目的compute(),当然你还可以接收到返回值之后再做些其他操作比如存入文件(Postprocess),这个过程就是使用了代理模式。

在平时用电脑也会碰到代理模式的应用:
远程代理:我们在国内因为GFW,所以不能访问 facebook,我们可以用翻墙(设置代理)的方法访问。访问过程是:
(1)用户把HTTP请求发给代理
(2)代理把HTTP请求发给web服务器
(3)web服务器把HTTP响应发给代理
(4)代理把HTTP响应发回给用户

二、静态代理

所谓静态代理, 就是在编译阶段就生成代理类来完成对代理对象的一系列操作。下面是代理模式的结构类图:

1、代理模式的参与者

代理模式的角色分四种:

主题接口: 即代理类的所实现的行为接口。
目标对象: 也就是被代理的对象。
代理对象: 用来封装真是主题类的代理类
客户端
下面是代理模式的类图结构:

2、代理模式的实现思路

代理对象和目标对象均实现同一个行为接口。
代理类和目标类分别具体实现接口逻辑。
在代理类的构造函数中实例化一个目标对象。
在代理类中调用目标对象的行为接口。
客户端想要调用目标对象的行为接口,只能通过代理类来操作。
3、静态代理的实例

下面以一个延迟加载的例子来说明一下静态代理。我们在启动某个服务系统时, 加载某一个类时可能会耗费很长时间。为了获取更好的性能, 在启动系统的时候, 我们往往不去初始化这个复杂的类, 取而代之的是去初始化其代理类。这样将耗费资源多的方法使用代理进行分离, 可以加快系统的启动速度, 减少用户等待的时间。

定义一个主题接口

public interface Subject {
  public void sayHello();
  public void sayGoodBye();
}

定义一个目标类, 并实现主题接口

public class RealSubject implements Subject {
  public void sayHello() {
    System.out.println("Hello World");
  }
  public void sayGoodBye() {
    System.out.println("GoodBye World");
  }
}

定义一个代理类, 来代理目标对象。

public class StaticProxy implements Subject {
  Private RealSubject realSubject = null;
  public StaticProxy() {}
  public void sayHello() {
    //用到时候才加载, 懒加载
    if(realSubject == null) {
      realSubject = new RealSubject();
    }
    realSubject.sayHello();
  }
  //sayGoodbye方法同理
  ...
}

定义一个客户端

public class Client {
  public static void main(String [] args) {
    StaticProxy sp = new StaticProxy();
    sp.sayHello();
    sp.sayGoodBye();
  }
}

以上就是静态代理的一个简单测试例子。感觉可能没有实际用途。然而并非如此。使用代理我们还可以将目标对象的方法进行改造, 比如数据库连接池中创建了一系列连接, 为了保证不频繁的打开连接,这些连接是几乎不会关闭的。然而我们编程总有习惯去将打开的Connection去close。 这样我们就可以利用代理模式来重新代理Connection接口中的close方法, 改变为回收到数据库连接池中而不是真正的执行Connection#close方法。其他的例子还有很多, 具体需要自己体会。

三、动态代理

动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。与静态处理类相比,动态类有诸多好处。

不需要为真实主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也很麻烦。如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;
使用一些动态代理的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性。
生成动态代理的方法有很多: JDK中自带动态代理, CGlib, javassist等。这些方法各有优缺点。本文主要探究JDK中的动态代理的使用和源码分析。

下面用一个实例讲解一下JDK中动态代理的用法:

public class dynamicProxy implements InvocationHandler {
  private RealSubject = null;
  public Object invoke(Object proxy, Method method, Object[] args){
    if(RealSubject == null) {
      RealSubject = new RealSubject();
    }
    method.invoke(RealSubject, args);
    return RealSubject;
  }
}

客户端代码实例

public class Client {
  public static void main(Strings[] args) {
    Subject subject = (Subject)Proxy.newInstance(ClassLoader.getSystemLoader(), RealSubject.class.getInterfaces(), new DynamicProxy());
    Subject.sayHello();
    Subject.sayGoodBye();
  }
}

从上面的代码可以看出, 要利用JDK中的动态代理。利用静态方法Proxy.newInstance(ClassLoader, Interfaces[], InvokeHandler)可以创建一个动态代理类。 newInstance方法有三个参数, 分别表示类加载器, 一个希望该代理类实现的接口列表, 以及实现InvokeHandler接口的实例。 动态代理将每个方法的执行过程则交给了Invoke方法处理。

JDK动态代理要求, 被代理的必须是个接口, 单纯的类则不行。JDK动态代理所生成的代理类都会继承Proxy类,同时代理类会实现所有你传入的接口列表。因此可以强制类型转换成接口类型。 下面是Proxy的结构图。

可以看出Proxy全是静态方法, 因此如果代理类没有实现任何接口, 那么他就是Proxy类型, 没有实例方法。

当然加入你要是非要代理一个没有实现某个接口的类, 同时该类的方法与其他接口定义的方法相同, 利用反射也是可以轻松实现的。

public class DynamicProxy implements InvokeHandler {
  //你想代理的类
  private TargetClass targetClass = null;
  //初始化该类
  public DynamicProxy(TargetClass targetClass) {
    this.targetClass = targetClass;
  }
  public Object invoke(Object proxy, Method method, Object[] args) {
    //利用反射获取你想代理的类的方法
    Method myMethod = targetClass.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
    myMethod.setAccessible(true);
    return myMethod.invoke(targetClass, args);
  }
}

四、JDK动态代理源码分析(JDK7)

看了上面的例子, 我们只是简单会用动态代理。但是对于代理类是如何创建出来的, 是谁调用Invoke方法等还云里雾里。下面通过分析

1、代理对象是如何创建出来的?

首先看Proxy.newInstance方法的源码:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  }
  //获取接口信息
  final Class<?>[] intfs = interfaces.clone();
  final SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
    checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  }
  //生成代理类
  Class<?> cl = getProxyClass0(loader, intfs);
  // ...OK我们先看前半截
  }

从源码看出代理类的生成是依靠getProxyClass0这个方法, 接下来看getProxyClass0源码:

private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
  //接口列表数目不能超过0xFFFF
  if (interfaces.length > 65535) {
    throw new IllegalArgumentException("interface limit exceeded");
  }
  //注意这里, 下面详细解释
    return proxyClassCache.get(loader, interfaces);
  }

对proxyClassCache.get的解释是: 如果实现接口列表的代理类已经存在,那么直接从cache中拿。如果不存在, 则通过ProxyClassFactory生成一个。
在看proxyClassCache.get源码之前,先简单了解一下proxyClassCache:

 private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

proxyClassCache是一个WeakCache类型的缓存, 它的构造函数有两个参数, 其中一个就是用于生成代理类的ProxyClassFactory, 下面是proxyClassCache.get的源码:

final class WeakCache<K, P, V> {
  ...
  public V get(K key, P parameter) {}
}

这里K表示key, P表示parameters, V表示value

public V get(K key, P parameter) {
  //java7 NullObject判断方法, 如果parameter为空则抛出带有指定消息的异常。 如果不为空则返回。
  Objects.requireNonNull(parameter);
  //清理持有弱引用的WeakHashMap这种数据结构,一般用于缓存
  expungeStaleEntries();
  //从队列中获取cacheKey
  Object cacheKey = CacheKey.valueOf(key, refQueue);
  //利用懒加载的方式填充Supplier, Concurrent是一种线程安全的map
  ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  if (valuesMap == null) {
    ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>());
      if (oldValuesMap != null) {
        valuesMap = oldValuesMap;
      }
    }
    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
  Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  Supplier<V> supplier = valuesMap.get(subKey);
  Factory factory = null;
  while (true) {
    if (supplier != null) {
    // 从supplier中获取Value,这个Value可能是一个工厂或者Cache的实
    //下面这三句代码是核心代码, 返回实现InvokeHandler的类并包含了所需要的信息。
    V value = supplier.get();
      if (value != null) {
        return value;
      }
    }
    // else no supplier in cache
    // or a supplier that returned null (could be a cleared CacheValue
    // or a Factory that wasn't successful in installing the CacheValue)
    //下面这个过程就是填充supplier的过程
    if(factory == null) {
      //创建一个factory
    }
    if(supplier == null) {
      //填充supplier
    }else {
      //填充supplier
    }
  }

while循环的作用就是不停的获取实现InvokeHandler的类, 这个类可以是从缓存中拿到,也可是是从proxyFactoryClass生成的。
Factory是一个实现了Supplier<V>接口的内部类。这个类覆盖了get方法, 在get方法中调用了类型为proxyFactoryClass的实例方法apply。这个方法才是真正创建代理类的方法。下面看ProxyFactoryClass#apply方法的源码:

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  for (Class<?> intf : interfaces) {
    /* Verify that the class loader resolves the name of this interface to the same Class object.*/
  Class<?> interfaceClass = null;
    try {
      //加载每一个接口运行时的信息
      interfaceClass = Class.forName(intf.getName(), false, loader);
    } catch (ClassNotFoundException e) {
    }
  //如果使用你自己的classload加载的class与你传入的class不相等,抛出异常
  if (interfaceClass != intf) {
    throw new IllegalArgumentException(
    intf + " is not visible from class loader");
  }
  //如果传入不是一个接口类型
    if (!interfaceClass.isInterface()) {
      throw new IllegalArgumentException(
        interfaceClass.getName() + " is not an interface");
    }
   //验证接口是否重复
    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
      throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
    }
  }
  String proxyPkg = null;   // package to define proxy class in
  /* Record the package of a non-public proxy interface so that the proxy class will be defined in the same package.
  * Verify that all non-public proxy interfaces are in the same package.
  */
  //这一段是看你传入的接口中有没有不是public的接口,如果有,这些接口必须全部在一个包里定义的,否则抛异常
  for (Class<?> intf : interfaces) {
    int flags = intf.getModifiers();
    if (!Modifier.isPublic(flags)) {
      String name = intf.getName();
      int n = name.lastIndexOf('.');
      String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
      if (proxyPkg == null) {
        proxyPkg = pkg;
      } else if (!pkg.equals(proxyPkg)) {
        throw new IllegalArgumentException(
          "non-public interfaces from different packages");
      }
    }
  }
  if (proxyPkg == null) {
    // if no non-public proxy interfaces, use com.sun.proxy package
    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  }
  /*
  * Choose a name for the proxy class to generate.
  */
  long num = nextUniqueNumber.getAndIncrement();
  //生成随机代理类的类名, $Proxy + num
  String proxyName = proxyPkg + proxyClassNamePrefix + num;
  /*
  * 生成代理类的class文件, 返回字节流
  */
  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
  try {
    return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
  } catch (ClassFormatError e) {
        //结束
        throw new IllegalArgumentException(e.toString());
      }
    }
  }

前文提到ProxyFactoryClass#apply是真正生成代理类的方法, 这其实是不准确的。源代码读到这里,我们会发现ProxyGenerator#generateProxyClass才是真正生成代理类的方法。根据Java class字节码组成(可以参见我的另一篇文章Java字节码学习笔记)来生成相应的Clss文件。具体ProxyGenerator#generateProxyClass源码如下:

  private byte[] generateClassFile() {
    /*
     * Step 1: Assemble ProxyMethod objects for all methods to
     * generate proxy dispatching code for.
     */
     //addProxyMethod方法,就是将方法都加入到一个列表中,并与对应的class对应起来
    //这里给Object对应了三个方法hashCode,toString和equals
    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);
    //将接口列表中的接口与接口下的方法对应起来
    for (int i = 0; i < interfaces.length; i++) {
      Method[] methods = interfaces[i].getMethods();
      for (int j = 0; j < methods.length; j++) {
        addProxyMethod(methods[j], interfaces[i]);
      }
    }
    /*
     * For each set of proxy methods with the same signature,
     * verify that the methods' return types are compatible.
     */
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
      checkReturnTypes(sigmethods);
    }
    /*
     * Step 2: Assemble FieldInfo and MethodInfo structs for all of
     * fields and methods in the class we are generating.
     */
     //方法中加入构造方法,这个构造方法只有一个,就是一个带有InvocationHandler接口的构造方法
     //这个才是真正给class文件,也就是代理类加入方法了,不过还没真正处理,只是先加进来等待循环,构造方法在class文件中的名称描述是<init>
  try {
    methods.add(generateConstructor());
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
      for (ProxyMethod pm : sigmethods) {
 //给每一个代理方法加一个Method类型的属性,数字10是class文件的标识符,代表这些属性都是private static的
        fields.add(new FieldInfo(pm.methodFieldName,
          "Ljava/lang/reflect/Method;",
           ACC_PRIVATE | ACC_STATIC));
        //将每一个代理方法都加到代理类的方法中
        methods.add(pm.generateMethod());
      }
    }
  //加入一个静态初始化块,将每一个属性都初始化,这里静态代码块也叫类构造方法,其实就是名称为<clinit>的方法,所以加到方法列表
      methods.add(generateStaticInitializer());
    } catch (IOException e) {
      throw new InternalError("unexpected I/O Exception");
    }
  //方法和属性个数都不能超过65535,包括之前的接口个数也是这样,
  //这是因为在class文件中,这些个数都是用4位16进制表示的,所以最大值是2的16次方-1
    if (methods.size() > 65535) {
      throw new IllegalArgumentException("method limit exceeded");
    }
    if (fields.size() > 65535) {
      throw new IllegalArgumentException("field limit exceeded");
    }
  //接下来就是写class文件的过程, 包括魔数, 类名,常量池等一系列字节码的组成,就不一一细说了。需要的可以参考JVM虚拟机字节码的相关知识。
    cp.getClass(dotToSlash(className));
    cp.getClass(superclassName);
    for (int i = 0; i < interfaces.length; i++) {
      cp.getClass(dotToSlash(interfaces[i].getName()));
    }
    cp.setReadOnly();
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(bout);
    try {
                    // u4 magic;
      dout.writeInt(0xCAFEBABE);
                    // u2 minor_version;
      dout.writeShort(CLASSFILE_MINOR_VERSION);
                    // u2 major_version;
      dout.writeShort(CLASSFILE_MAJOR_VERSION);
      cp.write(dout);       // (write constant pool)
                    // u2 access_flags;
      dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
                    // u2 this_class;
      dout.writeShort(cp.getClass(dotToSlash(className)));
                    // u2 super_class;
      dout.writeShort(cp.getClass(superclassName));
                    // u2 interfaces_count;
      dout.writeShort(interfaces.length);
                    // u2 interfaces[interfaces_count];
      for (int i = 0; i < interfaces.length; i++) {
        dout.writeShort(cp.getClass(
          dotToSlash(interfaces[i].getName())));
      }
                    // u2 fields_count;
      dout.writeShort(fields.size());
                    // field_info fields[fields_count];
      for (FieldInfo f : fields) {
        f.write(dout);
      }
                    // u2 methods_count;
      dout.writeShort(methods.size());
                    // method_info methods[methods_count];
      for (MethodInfo m : methods) {
        m.write(dout);
      }
                     // u2 attributes_count;
      dout.writeShort(0); // (no ClassFile attributes for proxy classes)
    } catch (IOException e) {
      throw new InternalError("unexpected I/O Exception");
    }
    return bout.toByteArray();
  }

经过层层调用, 一个代理类终于生成了。

2、是谁调用了Invoke?

我们模拟JDK自己生成一个代理类, 类名为TestProxyGen:

public class TestGeneratorProxy {
  public static void main(String[] args) throws IOException {
    byte[] classFile = ProxyGenerator.generateProxyClass("TestProxyGen", Subject.class.getInterfaces());
    File file = new File("/Users/yadoao/Desktop/TestProxyGen.class");
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(classFile);
    fos.flush();
    fos.close();
  }
}

用JD-GUI反编译该class文件, 结果如下:

import com.su.dynamicProxy.ISubject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class TestProxyGen extends Proxy
 implements ISubject
{
 private static Method m3;
 private static Method m1;
 private static Method m0;
 private static Method m4;
 private static Method m2;
 public TestProxyGen(InvocationHandler paramInvocationHandler)
  throws
 {
  super(paramInvocationHandler);
 }
 public final void sayHello()
  throws
 {
  try
  {
   this.h.invoke(this, m3, null);
   return;
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final boolean equals(Object paramObject)
  throws
 {
  try
  {
   return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final int hashCode()
  throws
 {
  try
  {
   return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final void sayGoodBye()
  throws
 {
  try
  {
   this.h.invoke(this, m4, null);
   return;
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final String toString()
  throws
 {
  try
  {
   return (String)this.h.invoke(this, m2, null);
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 static
 {
  try
  {
   m3 = Class.forName("com.su.dynamicProxy.ISubject").getMethod("sayHello", new Class[0]);
   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
   m4 = Class.forName("com.su.dynamicProxy.ISubject").getMethod("sayGoodBye", new Class[0]);
   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
   return;
  }
  catch (NoSuchMethodException localNoSuchMethodException)
  {
   throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  }
  catch (ClassNotFoundException localClassNotFoundException)
  {
   throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
 }
}

首先注意到生成代理类的构造函数, 它传入一个实现InvokeHandler接口的类作为参数, 并调用父类Proxy的构造器, 即将Proxy中的成员变量protected InvokeHander h进行了初始化。
再次注意到几个静态的初始化块, 这里的静态初始化块就是对代理的接口列表以及hashcode,toString, equals方法进行初始化。
最后就是这几个方法的调用过程, 全都是回调Invoke方法。
就此代理模式分析到此结束。

(0)

相关推荐

  • java设计模式—静态代理模式(聚合与继承方式对比)

    一.概述 1.目标:要在Tank的move()方法做时间代理及日志代理(可以设想以后还要增加很多代理处理),且代理间的顺序可活更换 2.思路: (1)聚合:代理类聚合了被代理类,且代理类及被代理类都实现了movable接口,则可实现灵活多变,具体看代码 (2)继承:继承不够灵活,随着功能需求增多,继承体系会非常臃肿.具体看代码 二.代码 1.Movable.java 2.Tank.java 3.TankTimeProxy.java 4.TankLogProxy.java 5.Tank2Time.

  • java设计模式笔记之代理模式

    代理(Proxy)模式: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 核心作用: 通过代理,控制对对象的访问. 可以详细控制访问某个(某类)对象的方法,在调用这个方法之前做前置处理,在调用这个方法之后做后置处理.即AOP的微观实现. AOP(Aspect Oriented Programming面向切面编程)的核心实现机制. 生活中的场景: 所谓代理,就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用

  • Java设计模式之代理模式(Proxy模式)介绍

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理. 设计模式中定义:为其他对象提供一种代理以控制对这个对象的访问. 为什么要使用代理模式 1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进

  • Java设计模式之代理模式_动力节点Java学院整理

    引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

  • Java设计模式之代理模式与装饰模式实例详解

    本文实例讲述了Java设计模式之代理模式与装饰模式.分享给大家供大家参考,具体如下: 之所以把这两种模式放在一起说,是因为我发现这了两种模式几乎一模一样! 从网上也搜了一些资料,发现两者还是有一些区别的.我们在学习的同时也把这种困惑搞清楚. 定义: 代理模式,为其他对象提供一种代理以控制对这个对象的访问. 装饰模式,动态地给一个对象添加一些额外的职责. 代理模式,很好理解,就是把一个对象再次封装,以后就对封装的对象访问就可以了. 因为代理对象已经取代了被代理对象. 装饰模式,给一个对象增加功能,

  • java设计模式学习之代理模式

    代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问. 代理模式结构图 模拟需求:3班小张喜欢1班小红,但是不认识小红,委托1班小明送给小红礼物. 1:创建一个小张和小明都能实现的接口. package ProxyModel; /** * 总的接口 * @author 我不是张英俊 * */ interface ISendGift { void GiveDolls(); void GiveFlowers(); void GiveChocolate(); } 2:实现小张送礼物.

  • Java使用设计模式中的代理模式构建项目的实例展示

    概念 代理模式(Proxy):代理模式其实就是多一个代理类出来,替原对象进行一些操作.比如咱有的时候打官司需要请律师,因为律师在法律方面有专长,可以替咱进行操作表达咱的想法,这就是代理的意思.代理模式分为两类:1.静态代理(不使用jdk里面的方法):2.动态代理(使用jdk里面的InvocationHandler和Proxy). 静态代理由程序员创建或工具生成代理类的源码,再编译代理类.所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了. 动态代理类的源

  • java设计模式-代理模式(实例讲解)

    代理模式是java最常见的设计模式之一.spring的aop就是使用了代理模式. 一般而言,代理模式分为静态代理和动态代理两种. 作为结构类的设计模式,作用在于不修改类内部代码的情况下,对类进行拓展,是对继承机制的一种补充. eg :下面就用户登录这个例子实现一下代理模式. 基本需求是:实现用户的登录和修改昵称功能. 上代码,先是IUser接口和user实现类 public interface IUser { //登录 void login(String userId,String passwo

  • 实例讲解Java设计模式编程中如何运用代理模式

    定义:  Provide a surrogate or placeholder for another object to control access to it. 为其他对象一种代理以控制对这个对象的访问. 一般描述: 一般包含的三个角色:抽象主题.具体主题.代理主题. 抽象主题:是一个抽象类或接口,是一个普通的业务类型定义. 具体主题:业务逻辑的具体执行者 代理角色:负责对真是角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现. 通用类图: 通用代码: package Pro

  • java设计模式之代理模式(Porxy)详解

    一.什么是代理模式(Porxy) 概念:代理模式就是为其他对象提供一种代理以控制对这个对象的访问. 现实生活中也有很多行为吻合代理模式.比如店外卖,客户在APP上下单后,店长会接单.这个时候店长可以选择自己去送这份外卖,也可以委托送餐员代理店长去送这份外卖.当然店长是可以自己送,但店长送了外卖店就没人看着了,而让送餐员代理送外卖就不会这样了.这里很显然店长是对象本尊(Subject),送餐员是代理对象(Proxy ),代理对象中有店长给的订单信息,比如送到哪里,几点之前要送到,这就说明代理对象中

随机推荐