Java设计模式之代理模式原理及实现代码分享

简介

Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术。生活中的方方面面都可以虚拟到代码中。代理模式所讲的就是现实生活中的这么一个概念:中介

代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

代理模式包含如下角色:

ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。

RealSubject:真实主题角色,是实现抽象主题接口的类。

Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

实现动态代理的关键技术是反射。

静态代理

代理模式有几种,虚拟代理,计数代理,远程代理,动态代理。主要分为两类,静态代理和动态代理。静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。

考虑这样的场景,管理员在网站上执行操作,在生成操作结果的同时需要记录操作日志,这是很常见的。此时就可以使用代理模式,代理模式可以通过聚合和继承两种方式实现:

/**方式一:聚合式静态代理
 * @author Goser  (mailto:goskalrie@163.com)
 * @Since 2016年9月7日
 */
//1.抽象主题接口
public interface Manager {
  void doSomething();
}
//2.真实主题类
public class Admin implements Manager {
  public void doSomething() {
    System.out.println("Admin do something.");
  }
}
//3.以聚合方式实现的代理主题
public class AdminPoly implements Manager{
  private Admin admin;

  public AdminPoly(Admin admin) {
    super();
    this.admin = admin;
  }

  public void doSomething() {
    System.out.println("Log:admin操作开始");
    admin.doSomething();
    System.out.println("Log:admin操作结束");
  }
}
//4.测试代码
    Admin admin = new Admin();
    Manager m = new AdminPoly(admin);
    m.doSomething();
//方式二:继承式静态代理
//与上面的方式仅代理类和测试代码不同
//1.代理类
public class AdminProxy extends Admin {
  @Override
  public void doSomething() {
    System.out.println("Log:admin操作开始");
    super.doSomething();
    System.out.println("Log:admin操作开始");
  }
}
//2.测试代码
    AdminProxy proxy = new AdminProxy();
    proxy.doSomething();

聚合实现方式中代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活。

比如,在管理员操作的同时需要进行权限的处理,操作内容的日志记录,操作后数据的变化三个功能。三个功能的排列组合有6种,也就是说使用继承要编写6个继承了Admin的代理类,而使用聚合,仅需要针对权限的处理、日志记录和数据变化三个功能编写代理类,在业务逻辑中根据具体需求改变代码顺序即可。

动态代理

一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。

但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。

JDK动态代理

实现

//1. 抽象主题
public interface Moveable {
  void move() throws Exception;
}
//2. 真实主题
public class Car implements Moveable {
  public void move() throws Exception {
    Thread.sleep(new Random().nextInt(1000));
    System.out.println("汽车行驶中…");
  }
}
//3.事务处理器
public class TimeHandler implements InvocationHandler {
  private Object target;
  public TimeHandler(Object target) {
    super();
    this.target = target;
  }
  /**
   * 参数:
   *proxy 被代理的对象
   *method 被代理对象的方法
   *args 方法的参数
   * 返回:
   *Object 方法返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    long startTime = System.currentTimeMillis();
    System.out.println("汽车开始行驶…");
    method.invoke(target, args);
    long stopTime = System.currentTimeMillis();
    System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");
    return null;
  }
}
//测试类
public class Test {
  public static void main(String[] args) throws Exception{
    Car car = new Car();
    InvocationHandler h = new TimeHandler(car);
    Class<!--?--> cls = car.getClass();
    /**
     *loader 类加载器
     *interfaces 实现接口
     *h InvocationHandler
     */
    Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
    m.move();
  }
}

代码讲解:

在测试代码中,Proxy.newProxyInstance()方法需要3个参数:类加载器(要进行代理的类)、被代理类实现的接口,事务处理器。所以先实例化Car,实例化InvocationHandler的子类TimeHandler,将各参数传入Proxy的静态方法newProxyInstance()即可获得Car的代理类,前面的静态代理,代理类是我们编写好的,而动态代理则不需要我们去编写代理类,是在程序中动态生成的。

JDK动态代理步骤

1.创建一个实现InvocationHandler接口的类,它必须实现invoke()方法

2.创建被代理的类及接口

3.调用Proxy的静态方法,创建一个代理类

4.通过代理调用方法

而为什么要进行如此操作,可以从Proxy和InvocationHandler的源码中找打答案。对源码不感兴趣的可以将下面的源码部分小节略过。

JDK动态代理原理与源码

newProxyInstance()方法的源码:

public static Object newProxyInstance(ClassLoader loader,
                     Class<!--?-->[] interfaces,
                     InvocationHandler h)
    throws IllegalArgumentException{
    if (h == null) {
      throw new NullPointerException();
    }
    final Class<!--?-->[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
      checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    /*查找或生成指定的代理类*/
    Class<!--?--> cl = getProxyClass0(loader, intfs);
    /*用指定的调用处理程序调用它的构造函数.*/
    try {
    //获得类的构造函数
      final Constructor<!--?--> cons =cl.getConstructor(constructorParams);
      final InvocationHandler ih = h;
      if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
       //当需要代理的类实现了一个非public的接口时,因为这样的接口需要特殊的权限,因此调用doPrivilege(native 修饰的方法)创建代理实例。
        return AccessController.doPrivileged(newPrivilegedAction<object>() {
          public Object run() {
            return newInstance(cons,ih);
          }
        });
      } else {
        return newInstance(cons,ih);
      }
    } catch (NoSuchMethodException e) {
      throw new InternalError(e.toString());
    }
}

可以看到,获得代理类的代码是

Classcl = getProxyClass0(loader,intfs);

并由此获得代理类的构造函数,生成代理类的实例返回给该方法的调用者。

继续跟进getProxyClass0()方法:

/** 生成代理类。调用该方法前必须使用checkproxyaccess方法执行权限检查。*/
  private static Class<!--?--> getProxyClass0(ClassLoader loader,
                     Class<!--?-->... interfaces) {
  //检查实现的接口数,65535这个数字好特殊,端口数好像也是这个,这个数字是由虚拟机所决定的,2^16-1个
  if (interfaces.length > 65535) {
      throw new IllegalArgumentException("interface limit exceeded");
    }
    // 如果代理类已经通过实现给定接口的类加载器创建了,则返回缓存中的该类的副本;否则将通过ProxyClassFactory创建代理类
    return proxyClassCache.get(loader, interfaces);
}

还是没有看到代理类是怎么生成的,只知道代理类是从proxyClassCache中取得的,这个变量是与缓存相关的一个对象,查看该变量的声明与初始化:

private static final WeakCache<classloader,>[], Class<!--?-->>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());</classloader,>

可以发现proxyClassCache是个用来缓存代理类的类变量,大家知道类变量的特点是与类一一对应,在一个虚拟机中类只有一个,对应着在一个虚拟机中类变量也只有一个,且在此处,在Proxy类被加载的时候就赋值了。在赋值操作的参数中有ProxyClassFactory()这么一个构造函数,这个是动态代理中的关键:生成代理类的类文件字节码。继续跟进去,找到代理类的生成之处了:

  /** 根据给定的类加载器和接口数组生成代理类的工厂类*/
  private static final class ProxyClassFactory
    implements BiFunction<classloader,class<?>[], Class<!--?-->>
  {
    // 所有代理类名称的前缀
    private static final String proxyClassNamePrefix = "$Proxy";

    //用于生成唯一代理类名称的下一个序号
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override
    public Class<!--?--> apply(ClassLoader loader,Class<!--?-->[] interfaces) {

      Map<class<?>, Boolean>interfaceSet = new IdentityHashMap<>(interfaces.length);
      for (Class<!--?--> intf : interfaces) {
        /* 验证类加载器将此接口的名称解析为实际对象的名称。*/
        Class<!--?--> interfaceClass =null;
        try {
          interfaceClass = Class.forName(intf.getName(),false, loader);
        } catch (ClassNotFoundException e) {
        }
        if (interfaceClass != intf) {
          throw new IllegalArgumentException(
            intf + " is not visible from classloader");
        }
        /* 验证类对象确实是一个接口。*/
        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;   // 代理类的包名

      /*记录非公开代理接口的包,以便将代理类定义在同一个包中。确认所有非公共代理接口都在同一个包中。*/
      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 fromdifferent packages");
          }
        }
      }

      if (proxyPkg == null) {
        // 如果没有非公开的代理接口,使用com.sun.proxy作为包名
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
      }

      /* 生成代理类名的序号*/
      long num = nextUniqueNumber.getAndIncrement();
      //生成全类名
      String proxyName = proxyPkg + proxyClassNamePrefix + num;

      /*生成代理类字节码 */
      byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,interfaces);
      try {
        return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
      } catch (ClassFormatError e) {
        throw new IllegalArgumentException(e.toString());
      }
    }
}

在ProxyClassFactory中,可以看到产生代理类的具体逻辑,大致上是,根据传递的被代理类及其实现的接口生成代理类的字节码加载到缓存中,但是加载到缓存中只是一个.java文件也不能用,所以底层还有编译等操作。到这里,可以大致的看清JDK中动态代理的面孔了,实现的步骤为:

1.创建代理类的源码;

2.对源码进行编译成字节码;

3.将字节码加载到内存;

4.实例化代理类对象并返回给调用者;

底层的代码我们看不到,但是我们可以查看其生成的字节码:

//获得字节码的测试方法
  byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy1", Car.class.getInterfaces());
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(System.getProperty("user.dir") + "\\$Proxy1.class");
      out.write(classFile);
      out.flush();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        out.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

//生成的字节码:
importcn.com.goser.proxy.imooc.staticproxy.Moveable;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy1 extends Proxy
 implements Moveable
{
 private static Method m1;
 private static Method m3;
 private static Method m0;
 private static Method m2;

 public $Proxy1(InvocationHandler paramInvocationHandler)
  throws
 {
  super(paramInvocationHandler);
 }

 public final boolean equals(Object paramObject)
  throws
 {
  try
  {
   return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }

 public final void move()
  throws Exception
 {
  try
  {
   this.h.invoke(this, m3, null);
   return;
  }
  catch (Exception localException)
  {
   throw localException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }

 public final int hashCode()
  throws
 {
  try
  {
   return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }

 public final String toString()
  throws
 {
  try
  {
   return (String)this.h.invoke(this, m2, null);
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
  }
  throw new UndeclaredThrowableException(localThrowable);
 }

 static
 {
  try
  {
   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
   m3 = Class.forName("cn.com.goser.proxy.imooc.staticproxy.Moveable").getMethod("move", new Class[0]);
   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
   return;
  }
  catch (NoSuchMethodExceptionlocalNoSuchMethodException)
  {
   throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  }
  catch (ClassNotFoundExceptionlocalClassNotFoundException)
  {
  }
  throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
 }
}

生成的字节码比较长,但是在字节码中最关键的信息是代理类的声明:

public final class $Proxy1 extends Proxy

可以看到生成的代理类是继承了Proxy类的,这就是说明了为什么使用JDK动态代理不能实现继承式动态代理,原因是Java不允许多继承,而生成的代理类本身就已经继承了Proxy类。

至此,JDK的动态代理的使用及底层原理分析完毕,揭下动态代理的神秘面纱,果然是枚美女。

至于最底层的native方法是怎么动态生成代理类的字节码我们也可以简单的模拟一下,先分析下模拟的步骤:首先要生成一段代理类的源码,然后将源码编译后生成代理类的实例返回给调用者。依据此步骤开始编写我们的模拟代码:

/**
 * JDK java.lang.reflect.Proxy的模拟
 * @author Goser  (mailto:goskalrie@163.com)
 * @Since 2016年9月7日
 */
public class Proxy {
  private static final String RT = "\r\n";
  public static Object newProxyInstance() throws Exception{
    //声明一段源码
    String sourceCode =
    "packagecn.com.goser.proxy.jdk.simulate;"+ RT +
    "importcn.com.goser.proxy.imooc.staticproxy.Admin;" + RT +
    "importcn.com.goser.proxy.imooc.staticproxy.Manager;" + RT +
    "//以聚合方式实现的代理主题" + RT +
    "public class $Proxy0 implementsManager{" + RT +
    "  privateAdmin admin;" + RT +
    "  public$Proxy0(Admin admin) {" + RT +
    "    super();" + RT +
    "    this.admin= admin;" + RT +
    "  }" + RT +
    "  publicvoid doSomething() {" + RT +
    "    System.out.println(\"Log:admin操作开始\");" + RT +
    "    admin.doSomething();" + RT +
    "    System.out.println(\"Log:admin操作结束\");" + RT +
    "  }" + RT +
    "}";
    String filename = System.getProperty("user.dir") + "/src/main/java/cn/com/goser/proxy/jdk/simulate/$Proxy0.java";
    File file = new File(filename);
    //使用org.apache.commons.io.FileUtils.writeStringToFile()将源码写入磁盘
    //编写到处,可以运行一下程序,可以在当前目录中看到生成的.java文件
    FileUtils.writeStringToFile(file,sourceCode);
    //获得当前系统中的编译器
    JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
    //获得文件管理者
    StandardJavaFileManager fileMgr =complier.getStandardFileManager(null, null, null);
    Iterable its =fileMgr.getJavaFileObjects(filename);
    //编译任务
    CompilationTask task = complier.getTask(null, fileMgr, null, null, null, its);
    //开始编译,执行完可在当前目录下看到.class文件
    task.call();
    fileMgr.close();
    //load到内存
    ClassLoader loader = ClassLoader.getSystemClassLoader();
    Class cls = loader.loadClass("cn.com.goser.proxy.jdk.simulate.$Proxy0");
    //生成代理类对象
    Constructor ct = cls.getConstructor(Admin.class);
    return ct.newInstance(new Admin());
  }
}
class test{
  public static void main(String[] args) throws Exception {
    Manager m = (Manager)Proxy.newProxyInstance();
    m.doSomething();
  }
}

运行测试代码,结果和手工编写的结果一致,完成了JDK中动态代理的实现模拟。

cglib动态代理

前面分析到,因为Java只允许单继承,而JDK生成的代理类本身就继承了Proxy类,因此,使用JDK实现的动态代理不能完成继承式的动态代理,但是我们可以使用cglib来实现继承式的动态代理。

大名鼎鼎的Spring中就含有cglib动态代理,在此也以Spring中自带的cglib完成动态代理的实现:

//1.具体主题
public class Train{
  public void move(){
    System.out.println("火车行驶中…");
  }
}
//2.生成代理
public class CGLibProxy implements MethodInterceptor {
  private Enhancer enhancer = new Enhancer();
  public Object getProxy(Class<!--?--> clazz){
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);
    return enhancer.create();
  }
  /**
   * 拦截所有目标类方法的调用
   * 参数:
   * obj目标实例对象
   *method 目标方法的反射对象
   * args方法的参数
   * proxy代理类的实例
   */
  public Object intercept(Object obj, Method method, Object[] args,
      MethodProxy proxy) throws Throwable {
    //代理类调用父类的方法
    System.out.println("日志开始");
    proxy.invokeSuper(obj, args);
    System.out.println("日志结束");
    return null;
  }
}
//3.测试
public class Test {
  public static void main(String[] args) {
    CGLibProxy proxy = new CGLibProxy();
    Train t = (Train) proxy.getProxy(Train.class);
    t.move();
  }
}

小结

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理。Proxy 很美很强大,但是仅支持 interface 代理。Java 的单继承机制注定了这些动态代理类们无法实现对 class 的动态代理。好在有cglib为Proxy提供了弥补。class与interface的区别本来就模糊,在java8中更是增加了一些新特性,使得interface越来越接近class,当有一日,java突破了单继承的限制,动态代理将会更加强大。

以上就是本文关于Java设计模式之代理模式原理及实现代码分享的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:快速理解Java设计模式中的组合模式、Java设计者模式简单工厂模式解析、Java设计模式之访问者模式使用场景及代码示例等,有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

(0)

相关推荐

  • Java设计模式笔记之抽象工厂代码示例

    上一篇说到了工厂模式,那么学习了工厂模式,抽象工厂也得学习一下.实际上,抽象工厂模式实际上就是在工厂模式的基础上再嵌套一层工厂模式而已,通过父工厂制造子工厂.只是,也并不完全是嵌套一层,各个工厂会被抽象成一个集多个工厂共同点的抽象类.通过工厂制造器,创建出该抽象工厂的子类. 好比如说,一个博客页面有个换肤系统.那么假如有两套风格,黑和白.那么,我选择了黑色风格的,实际这步就相当通过换肤系统这个工厂制造器,创建出一个黑色主题的工厂,该黑色主题的工厂内可以生产各种黑色风格的产品,比如黑色头像挂饰,黑

  • java 设计模式(DAO)的实例详解

    java 设计模式(DAO)的实例详解 应用场景:在Java程序中,经常需要把数据持久化,也需要获取持久化的数据,但是在进行数据持久化的过程中面临诸多问题(如:数据源不同.存储类型不同.供应商不同.访问方式不同等等),请问如何能以统一的接口进行数据持久化的操作? 其实这个我没学号(≧ ﹏ ≦).我的理解就是一个产品面向的用户不是单一的,所以我们要兼容许多情况如前面提到的数据源不同.存储类型不同.供应商不同.访问方式不同等等. ★ 解决方案 DAO的理解: 1.DAO其实是利用组合工厂模式来解决问

  • Java设计模式之访问者模式使用场景及代码示例

    Java设计模式访问者模式 模式概念 访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作.访问者模式适用于数据结构相对稳定算法又易变化的系统,若系统数据结构对象易于变化,则不适合使用访问者模式.访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者. Visitor应用场景 一定会有的疑问:visitor和iterator的区别: visitor可以访问不同的对象(只需要在Element定义对应的accept),但是Ite

  • 快速理解Java设计模式中的组合模式

    组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 通用类图如下: 组合模式的包含角色: ● Component 抽象构件角色 定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. ● Leaf 叶子构件 叶子对象,其下再也没有其他的分支,也就是遍历的最

  • Java设计模式之静态工厂模式详解

    本文实例讲述了Java设计模式之静态工厂模式.分享给大家供大家参考,具体如下: 静态工厂模式(static factory)也叫简单工厂模式. 涉及到3个角色:工厂类角色,抽象产品类角色和具体产品类角色. 抽象产品类可以使用接口或者父类来描述产品对象的行为特征. 具体产品类就是某一具体的对象. 静态工厂类有一个静态的方法,含有判断逻辑,决定要创建哪一种具体的产品对象. 其设计模式如下: 抽象产品类  IProduct package org.test.design.sf; public inte

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

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

  • Java设计模式之代理模式原理及实现代码分享

    简介 Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术.生活中的方方面面都可以虚拟到代码中.代理模式所讲的就是现实生活中的这么一个概念:中介. 代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用. 代理模式包含如下角色: ISubject:抽象主题角色,是一个接口.该接口是对象和它的代理共用的接口. RealSubject:真实主题角色,是实现抽象主题接口的类. Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实

  • Java设计模式之策略模式原理与用法实例详解

    本文实例讲述了Java设计模式之策略模式原理与用法.分享给大家供大家参考,具体如下: 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化.其中JDK里面的TreeSet类和TreeMap类就用到了策略模式.这两个类是带排序的集合类,其中排序的规则就相当于策略模式里定义的一系列算法,而集合类就相当于是策略模式里的环境类,供用户使用,用只知道TreeSet和TreeMap是带排序的,至于怎么排序的,是由排序的算法决定的. 策略模式

  • Java设计模式之代理模式与@Async异步注解失效的解决

    目录 JDK动态代理实现自定义异步注解(@Async) SpringAOP实现自定义异步注解 Spring的异步注解@Async失效分析 自定义注解实现方式 JDK动态代理实现自定义异步注解(@Async) 实现思路: 首先自定义一个注解,命名为:ExtAsync 实现一个接口,这个接口的实现类就是被代理类 实现jdk的InvocationHandler接口,根据反射获取目标方法的信息,判断是否有异步注解,如果有则另起一个线程异步执行去. 1.异步注解 @Target({ElementType.

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

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

  • 详解JAVA设计模式之代理模式

    什么是设计模式(Design Pattern)? 设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结. 代理模式的定义? 代理模式就是为其他对象提供一种代理,以控制对这个对象的访问. 代理对象起到中介作用,可去掉功能服务或增加额外的服务. 代理对象和目标对象的关系? 代理对象:增强后的对象 目标对象:被增强的对象 他们不是绝对的,会根据情况发生变化. 代理模式的两种实现方式? 1.静态代理:代理和被代理对象在代理之前是确定的,它们都实现相同的接口或者继承相同的抽象类. 2

  • 浅谈JAVA设计模式之代理模式

    代理模式 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. 介绍 意图: 为其他对象提供一种代理以控制对这个对象的访问. 主要解决: 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时

  • Java设计模式之代理模式详解

    一.代理模式 代理模式就是有一个张三,别人都没有办法找到他,只有他的秘书可以找到他.那其他人想和张三交互,只能通过他的秘书来进行转达交互.这个秘书就是代理者,他代理张三. 再看看另一个例子:卖房子 卖房子的步骤: 1.找买家 2.谈价钱 3.签合同 4.和房产局签订一些乱七八糟转让协议 一般卖家只在签合同的时候可能出面一下,其他的1,2,4都由中介去做.那你问这样有什么用呢? 首先,一个中介可以代理多个卖房子的卖家,其次,我们可以在不修改卖家的代码的情况下,给他实现房子加价.打广告等等夹带私货的

  • Java设计模式之代理模式详细解读

    目录 Java设计模式-代理模式 什么是代理模式? 代理模式-UML图: 源代码: 运行结果: 总结: 应用实例: 优点: 缺点: 使用场景: Java设计模式-代理模式 什么是代理模式? 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. 所谓的代理严格来讲就是两个子类共同实现一个接口,其中一个子类负责真实业务实现,另一个辅助完成主类业务逻辑操作. 代理模式-UML图: 源

  • java设计模式责任链模式原理案例详解

    目录 引言 责任链模式定义 类图 角色 核心 示例代码 1.对请求处理者的抽象 2.对请求处理者的抽象 3.责任链的创建 责任链实现请假案例 案例类图 可扩展性 纯与不纯的责任链模式 纯的责任链模式 不纯的责任链模式 责任链模式主要优点 职责链模式的主要缺点 适用场景 模拟实现Tomcat中的过滤器机制 运行过程如下 分析Tomcat 过滤器中的责任链模式 引言 以请假流程为例,一般公司普通员工的请假流程简化如下: 普通员工发起一个请假申请,当请假天数小于3天时只需要得到主管批准即可:当请假天数

随机推荐