代理模式

所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式是一种结构性设计模式。当客户端不想直接调用主题对象,而希望主题对象的行为前后加上预处理或者后续处理时,则可以使用代理模式。

代理模式的三种角色

主题抽象类

主题抽象类定义了主题对象的行为,下面的例子中主题抽象类定义了主题对象的request行为。

  1.  
    abstract public class Subject{
  2.  
    abstract public void request();
  3.  
    }

实际主题类

实际主题类继承了抽象主题类Subject,实现了抽象主题类中的行为request。实际主题类就是AOP中的目标对象。

public class RealSubject extends Subject{
public void request(){
System.out.println("RealSubject");
}
}

代理类

代理了继承了抽象主题类,同时关联了实际主题类。代理类中定义了preRequest和postRequest方法,对实际主题类中的request方法实施了控制。代理类对应Spring AOP中的ProxyFactoryBean类,用来生成代理对象。

public class ProxySubject extends Subject{
private RealSubject realSubject;
public void request(){
preRequest(); //自定定义的方法,方法中可以实现一些想在请求之前就要完成的逻辑
if(realSubject==null){
realSubject = new RealSubject();
}
realSubject.request();
postRequest(); //自定定义的方法,方法中可以实现一些想在请求之后想要完成的逻辑
} }

两种代理

按照代理的创建时期,代理类可以分为两种。

静态代理

由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。上面的例子就是静态代理,与动态代理相比,静态代理有一些局限性,比如:有多少目标类就有多少proxy;在目标类中有多少方法,在代理类中就有多少方法。

动态代理

在程序运行时,运用反射机制动态创建而成。JDK动态代理中包含一个类和一个接口:

  1. InvocationHandler接口:

    public interface InvocationHandler {
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
    }
    /*参数说明:
    Object proxy:指被代理的对象。
    Method method:要调用的方法
    Object[] args:方法调用时所需要的参数
    */

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。

  1. Proxy类:

    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    /*参数说明:
    ClassLoader loader:类加载器
    Class<?>[] interfaces:得到全部的接口
    InvocationHandler h:得到InvocationHandler接口的子类实例
    */

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

JDK动态代理

  1.  
    public interface Subject {
  2.  
    public void request();
  3.  
    }
  1.  
    public class SubjectImpl implements Subject {
  2.  
    public void request(){
  3.  
    System.out.println("RealSubject");
  4.  
    }
  5.  
    }
public class SubjectProxy implements InvocationHandler {
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
} @Override
/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("事物开始");
//执行方法
result=method.invoke(target, args);
System.out.println("事物结束");
return result;
} }
  1.  
    public static void main(String[] args) {
  2.  
    SubjectProxy proxy = new SubjectProxy();
  3.  
    Subject subjectProxy = (Subject) proxy.bind(new SubjectImpl());
  4.  
    subjectProxy.request();
  5.  
    }

DK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

CGLIB动态代理

  1.  
    public interface Subject {
  2.  
    public void request();
  3.  
    }
public class SubjectImpl{
public void request(){
System.out.println("RealSubject");
}
}
public class SubjectCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
} @Override
// 回调方法
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;
} }
  1.  
    public static void main(String[] args) {
  2.  
    SubjectCglib cglib=new SubjectCglib();
  3.  
    SubjectImpl subjectCglib=(SubjectImpl)cglib.getInstance(new SubjectImpl());
  4.  
    subjectCglib.request();
  5.  
    }

Spring两种代理方式

    1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。 
      优点:因为有接口,所以使系统更加松耦合 
      缺点:为每一个目标类创建接口
    2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。 
      优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。 
      缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。 
      动态代理是Spring AOP技术的基础,掌握了动态代理,接下来学习AOP会更加得心应手。

Spring中的代理模式的更多相关文章

  1. spring设计模式_代理模式

    代理模式应该是Spring核心设计模式之一了 先说下代理模式特性: 1.有代理人和被代理人 2.对于被代理的人来说,这件事情是一定要做的,但是我又不想做,所有就找代理人来做. 3.需要获取到被代理人的 ...

  2. Objective-C中的委托(代理)模式

    我个人更喜欢把委托(Delegate)模式称为代理(Proxy)模式.还是那句话,第一次接触代理模式是在Java中接触的,在Java中实现代理模式和接口是少不了的.当时学习Spring的时候用到了接口 ...

  3. (转)轻松学,Java 中的代理模式及动态代理

    背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...

  4. Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式

    Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...

  5. OC中的代理模式

    OC中的代理模式,关于代理模式,如果还有同学不太清楚的话,就自己去补充知识了,这里就不做介绍了,这里只介绍OC中是如何实现代理模式的.这里举一个简单的例子:小孩类,护士类,保姆类,其中小孩类有两个方法 ...

  6. 002-创建型-04-建造者模式(Builder)、JDK1.7源码中的建造者模式、Spring中的建造者模式

    一.概述 建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象 ...

  7. 简介Python设计模式中的代理模式与模板方法模式编程

    简介Python设计模式中的代理模式与模板方法模式编程 这篇文章主要介绍了Python设计模式中的代理模式与模板方法模式编程,文中举了两个简单的代码片段来说明,需要的朋友可以参考下 代理模式 Prox ...

  8. 「补课」进行时:设计模式(5)——从 LOL 中学习代理模式

    1. 前文汇总 「补课」进行时:设计模式系列 2. 从 LOL 中学习代理模式 我是一个很喜欢玩游戏的人,虽然平时玩游戏的时间并不多,但我也是一个忠实的 LOL 的爱好者,就是段位有点惨不忍睹,常年倔 ...

  9. Spring框架_代理模式(静态代理,动态代理,cglib代理)

    共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下:                 ...

随机推荐

  1. sqlserver 2012 IDE中 Windows身份验证连接服务器报错 ,Login failed for user 'xxx\Administrator'. 原因: 找不到与提供的名称匹配的登录名。

    问题描述: 本地装了两个实例,一个是SQLEXPRESS,可以正常操作.但是另一个开发常用的实例MSSQLSERVER却连Windows身份验证都报错,报的错误也是很奇葩,怎么会找不到Administ ...

  2. Programming 2D Games 读书笔记(第三章)

      示例一:DirectX Window Graphics类用于初始化Direct 3D 主流程: 仅需要粗体部分 try{ // Create Graphics object graphics = ...

  3. VS2015开发环境的安装和配置 2016-07-03更新

    创建日期:2016-07-03 一.简介 为了避免网上乱七八糟的过时介绍,避免误导初学者,这次把至2016年6月底C#开发环境各种版本的更新和安装过程重新整理一下贡献出来.目的是为了让对C#感兴趣的初 ...

  4. 对ORM的支持 之 8.4 集成JPA ——跟我学spring3

    8.4  集成JPA JPA全称为Java持久性API(Java Persistence API),JPA是Java EE 5标准之一,是一个ORM规范,由厂商来实现该规范,目前有Hibernate. ...

  5. xcode 不能选择模拟器

    重新安装了xcode后,程序无法运行,不能选择模拟器 或者 设备? 1.你之所以选择不了模拟器或者设备,是因为你工程中的iOS Deployment Target设置不对.比如你装的是xcode4.0 ...

  6. java 反射原理写了一个赋值和取值通用类

    首先了解一下反射的原理,什么是反射?所谓的反射就是指java 语言在运行时拥有一项自观的能力,反射能使你得到装载到 jvm 中的类的内部信息,它不需要你在编码的时候就知道所需类的内部信息,允许程序执行 ...

  7. 判断listview滑动方向的代码片段

    mListView.setOnScrollListener(new OnScrollListener() { private int lastIndex = 0; @Override public v ...

  8. SimpleAdapter和AutoCompleteTextView配合使用

     修改后成为这样→    package com.kale.autocompletetextview; import java.util.ArrayList; import java.util.Has ...

  9. 记录一个简单的vue页面实现

    <template> <div class="userView"> <!-- 页眉颜色统一 --> <div class="bu ...

  10. springboot 表单校验

    实体: @Entity public class User implements Serializable { /** * 编号 */ @Id @GeneratedValue private Long ...