Java代理模式实例详解【静态代理与动态代理】

本文实例讲述了Java代理模式。分享给大家供大家参考,具体如下:

即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。

Java的代理模式是Java中比较常用的设计模式,分为2中代理:静态代理与动态代理(JDK动态代理和cglib动态代理)

优点:

  • 职责清晰 真实角色只需关注业务逻辑的实现,非业务逻辑部分,后期通过代理类完成即可。
  • 高扩展性 不管真实角色如何变化,由于接口是固定的,代理类无需做任何改动。

缺点:

  • 很明显的一点就是反射机制,没有高安全性,性能也相对来讲低一些。

代理模式这种设计模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。代理对象代为执行目标对象的方法,并在此基础上进行相应的扩展。看起来是有点拗口,首先介绍一个原则:开闭原则(对扩展开放,对修改关闭)。一种好的设计模式甚至是架构,都是在不修改原有形态的基础上扩展出新的功能。

事例场景:

小张是一个普普通通的码农,每天勤勤恳恳地码代码。某天中午小张刚要去吃饭,一个电话打到了他的手机上。“是XX公司的小张吗?我是YY公司的王AA”。“哦,是王总啊,有什么事情吗?”。沟通过后,小张弄明白了,原来客户有个需求,刚好负责这方面开发的是小张,客户就直接找到了他。不过小张却没有答应客户的请求,而是让客户找产品经理小李沟通。

是小张着急去吃面而甩锅吗?并不是,只是为了使故事可以套到代理模式上。我们先看一下代理模式的定义: * 为其他对象提供一种代理,以控制对这个对象的访问。(Provide a surrogate or placeholder for another object to control access to it)

对照定义,码农小张可以映射为其他对象,产品经理小李为小张的代理。我们通过JAVA代码,表述上面事例。

一、静态代理

什么是静态代理:静态代理就是在程序运行前就已经确定代理类与代理对象的代理模式

静态代理模式就是如上图所示,构造三个类实现他们的关系。

首先会思考的一点就是为什么需要实现同一个接口,如果不实现同一个接口,一样可以“代理”功能,所以为什么非要实现同一个接口。我个人认为不实现统一接口的话应该叫做聚合而不是代理;然后,实现统一接口能够使代理类与被代理类之间的联系,提高代码的复用性又能解耦。

package staticProxy;
/**
*接口
*/
public interface DAOInterface {
  public void add();
  public void delete();
  public void update();
  public void query();
}
package staticProxy;
/**
*被代理类
*/
public class UserDao implements DAOInterface{
  @Override
  public void add() {
    System.out.println("在目标对象中执行add");
  }
  @Override
  public void delete() {
    System.out.println("在目标对象中执行delete");
  }
  @Override
  public void update() {
    System.out.println("在目标对象中执行update");
  }
  @Override
  public void query() {
    System.out.println("在目标对象中执行query");
  }
}
package staticProxy;
/**
 * 代理类
 *
 */
public class UserDaoProxy implements DAOInterface{
  UserDao userDao = null;
  public UserDaoProxy(UserDao userDao){
    this.userDao = userDao;
  }
  @Override
  public void add() {
    userDao.add();
    System.out.println("记录日志add");
  }
  @Override
  public void delete() {
    userDao.delete();
    System.out.println("记录日志delete");
  }
  @Override
  public void update() {
    userDao.update();
    System.out.println("记录日志update");
  }
  @Override
  public void query() {
    userDao.query();
    System.out.println("记录日志query");
  }
}

静态代理就是写死了在代理对象中执行这个方法前后执行添加功能的形式,每次要在接口中添加一个新方法,则需要在目标对象中实现这个方法,并且在代理对象中实现相应的代理方法;利用Java的反射机制,动态的调用生成代理对象,就能完成动态代理的需求。

二、动态代理

1、JDK动态代理

在代理类管理器的新建代理实例方法中,必须要获得类的加载器、类所实现的接口、还有一个拦截方法的句柄。

在句柄的invoke中如果不调用method.invoke则方法不会执行。在invoke前后添加通知,就是对原有类进行功能扩展了。创建好代理对象之后,proxy可以调用接口中定义的所有方法,因为它们实现了同一个接口,并且接口的方法实现类的加载器已经被反射框架获取到了。

package JDKAgency;
/**
 * DAO接口
 */
public interface DAO {
  void add();
  void update();
  void delete();
  void query();
}
package JDKAgency;
/**
 * DAO的实现类
 */
public class DAOImpl implements DAO {
  @Override
  public void add() {
    System.out.println("添加的方法");
  }
  @Override
  public void update() {
    System.out.println("更新的方法");
  }
  @Override
  public void delete() {
    System.out.println("删除的方法");
  }
  @Override
  public void query() {
    System.out.println("查询的方法");
  }
}
package JDKAgency;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 代理类管理器
 */
public class ProxyManager implements InvocationHandler {//动态代理的核心处理器接口
  private Object object;
  public ProxyManager(Object object) {
    this.object = object;
  }
  public Object createNewInstance() {
    Object o = Proxy.newProxyInstance(object.getClass().getClassLoader(),//真实对象的类加载器
        object.getClass().getInterfaces(),//真实对象的所有接口
        this);//代理对象
    return o;
  }
  @Override        //代理对象   执行业务的方法   参数
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("before......权限检测");//前置通知
    Object invoke = method.invoke(object, args);//动态调用执行方法
    System.out.println("after......日志监控");//后置通知
    return invoke;
  }
}
package JDKAgency;
/**
 * 测试
 */
public class JTest {
  public static void main(String[] args) {
    //创建真实对象
    DAO dao = new DAOImpl();
    DAO o =(DAO) manager.createNewInstance();
//JDK动态代理是代理的接口,因此强制转换应该转换为接口,而不是实现类,若强制转换实现类就会抛出ClassCastException,好比ArrayList与LinkedList实现统一接口List,两者也不能相互转换,但都可以向上转型。
    o.add();
    o.query();
  }
}

注意:JDK动态代理是代理的接口,因此强制转换应该转换为接口,而不是实现类,若强制转换实现类就会抛出ClassCastException,好比ArrayList与LinkedList实现统一接口List,两者也不能相互转换,但都可以向上转型。

补充:

JavaJDK动态代理报错java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to *。

javaJDK动态代理是Java原生代理模式。

注意:JDK动态代理是代理的接口,因此强制转换应该转换为接口,而不是实现类,若强制转换实现类就会抛出ClassCastException,好比ArrayList与LinkedList实现统一接口List,两者也不能相互转换,但都可以向上转型。

正确的转型方案:

//创建处理器对象
ProxyManager manager = new ProxyManager(dao);
//生成动态代理对象
// DAO o = (DAO) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), manager);

2、cglib动态代理

cglib动态代理是web应用框架常用的一种动态代理方式。cglib是动态生成被代理类的子类,注意:是子类。

他需要先引入asm与cglib的jar包。如下图:

接着废话不多说,看代码分析:

package CGlibAgency;
/**
 * 被代理类
 */
public class User {
  public void saveUser(){
    System.out.println("保存对象。");
  }
  public void updateUser(){
    System.out.println("修改对象。");
  }
}
package CGlibAgency;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * 代理类管理器
 */
public class Interceptor implements MethodInterceptor {//cgLib需要实现MethodInterceptor接口,cgLib是基于类的,动态的生成代理类(被代理类的子类)
  private Enhancer enhancer = new Enhancer();//Enhancer是Cglib代理的重要对象
  public Object createProxy(Class superClass){
    enhancer.setSuperclass(superClass);//获取父类的Class
    enhancer.setCallback(this);//设置方法的回调,类似于JDK动态代理中的Proxy与InvocationHandler实现类的绑定回调
    return enhancer.create();//返回代理类的对象
  }
  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("'权限验证'");
    Object aSuper = methodProxy.invokeSuper(o, objects);//通过虚拟的代理对象的代理方法调用父类的方法,参数中一个是父类,一个是所有的子类对象数组(??)
    System.out.println("'日志收集'");
    return aSuper;
  }
}
package CGlibAgency;
/**
 * 测试类
 */
public class JTest {
  public static void main(String[] args) {
    Interceptor interceptor = new Interceptor();//创建代理管理对象
    Object proxy = interceptor.createProxy(User.class);//创建一个代理类
    System.out.println(User.class.getTypeName());//查看代理类的类型
    User user = (User) proxy;//转型,子类自动向上转型
    user.saveUser();
    user.updateUser();
  }
}

总结:

代理模式不仅可以降低模块儿之间的耦合,还能做到高复用,简化代码等。spring的AOP模块就是最直观的代理模式,使用了动态代理来实现,在spring中的许多模块中都具有动态代理的影子。

更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

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

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

  • JAVA 静态代理模式详解及实例应用

    JAVA 静态代理模式 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问. 代理模式说白了就是"真实对象"的代表,在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途. 在这实现代码之前,先讲一个简单的生活故事,我们都知道我们周边有很多公司有房屋买卖或租赁的业务,比如链家(LianJia),但链家本身是不存在任何实际房屋资产的,他所售卖租赁的房屋均需要房屋产权所有人(HomeMaster)提供,才得以实现公司的房源需求:同时公司要的卖房租房业务均需要公司

  • JAVA动态代理模式(从现实生活角度理解代码原理)

    所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个类. InvocationHandler类 public Object invoke(Object obj,Method method,Object[] obs) 其中第一个参数 obj 指的是代理类,method是被代理的方法,obs是指被代理的方法的参数组.此方法由代理类来实现. Proxy类

  • 详解java动态代理模式

    本文针对java动态代理进行知识点整理,具体内容如下 一. JAVA的动态代理(比较官方说法) 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处 理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的 对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提 供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工

  • Java设计模式之动态代理模式实例分析

    本文实例讲述了Java设计模式之动态代理模式.分享给大家供大家参考,具体如下: 前面介绍了静态代理模式,动态代理比静态代理模式更加强大.它能在程序运行时动态的生成代理对象.所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface.当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作. 动态代理的角色和静态代理的角色一样: ① 抽象角色:

  • 代理模式之Java动态代理实现方法

    今天一个偶然的机会我突然想看看JDK的动态代理,因为以前也知道一点,而且只是简单的想测试一下使用,使用很快里就写好了这么几个接口和类:接口类:UserService.java 复制代码 代码如下: package com.yixi.proxy;public interface UserService {    public int save() ;    public void update(int id);} 实现类:UserServiceImpl.java 复制代码 代码如下: packag

  • java代理模式与动态代理模式详解

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费.但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的.这点很重要!

  • 详解Java 中的三种代理模式

    代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法. 举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理

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

    java 代理模式详解 前言: 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为"代理"的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务. 简单来说代理模式就是通过一个代理对象去访问一个实际对象,并且可以像装饰模式一样给对象添加一些功能. 静态代理 所谓静态代理即在程序运行前代理类就已经存在,也就是说我们编写代码的时候就已经把代理类的代码写好了,而动态代理则

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

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

随机推荐