`
flyingdutchman
  • 浏览: 359002 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

设计模式:代理模式之动态代理

阅读更多
        代理是一种常用的设计模式,其目的是为其他对象提供一种代理以控制(外部对象)对这个被被代理对象的的访问。由代理类负责为委托类(即被代理类)对象做一些用户处理的操作(如权限限制)或执行完之后的后续操作。
        代理模式的特征是:代理类与委托类(即被代理类)有同样的接口,代理类主要负责为委托类(即被代理类)预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
        线面我们来看一下代理模式的类图:

        我们这里主要学习以下动态代理模式,动态代理是在运行时,运用反射机制动态创建代理类。
        常用的动态代理分为JDK动态代理和CGLIB动态代理。对于这两种动态代理,JDK的动态代理需要依靠接口实现,如果有些类并没有实现接口,则不能使用JDK动态代理;而CGLIB是针对类来实现代理的,其原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,故不能对final修饰的类进行代理。
        就我们熟知的Spring框架中的AOP默认就是使用JDK动态代理的,如果想强制使用CGLIB实现代理,那就需要添加CGLIB库,并在Spring配置中加入:
              <aop:aspectj-autoproxy proxy-target-class="true"/>
        

        就性能而言,CGLIB动态代理要较JDK的K动态代理高一些。

        JDK动态代理
        在JDK的动态代理中,除了要实现的接口外,外特别关注java.lang.reflect包下的一个类Proxy和动态代理要实现的接口InvocationHandler。
        Proxy是Java动态代理的主类,它提供了一些静态方法,用于为一组儿接口动态地生成代理类及其对象:
              //获取指定的代理对象关联的调用处理器
              static InvocationHandler getInvocationHandler(Object proxy)
              //获取关联于指定类加载器和一组儿接口的动态代理类的对象
              static Class getProxyClass(ClassLoader loader,Class[] interfaces)
              //判断指定的类是否是一个动态代理类
              static boolan isProxyClass(Class cl)
              /**
               * 非常重要的接口:用于为指定的类加载器、一组儿接口和嗲用处理器生成
               * 动态代理累的实例
               */
              static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
        

        再来看一下InvocationHandler接口,它主要定义了一个invoke方法,用于处理动态代理类对象上的方法调用。通常开发者需要实现该接口并在其方法内实现对委托类(被代理类)对象的代理访问:
              /**
               * 该方法负责处理动态代理类上的方法调用。
               * @Param proxy: 代理类的实例
               * @Param method: 被调用的方法对象
               * @Param args: 调用参数
               */
              Object invoke(Object proxy,Method method,Object[] args)
        

        具体代码如下:
 package org.pattern;

 /**
  * 卖货接口
  * @author Jacky.Chen
  *
  */
 public interface ISell {
	
	    /**
	     * 卖货
	     */
	    void sell();

 }
 

 package org.pattern;

 /**
  * 销售商,实现了ISell接口
  * @author JackyChen
  *
  */
 public class Vendor implements ISell{

	   @Override
	   public void sell(){
		  System.out.println("今天,俺又卖了一件货品!");		
	   }

 }

 

 package org.pattern;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

 /**
  * 销售商代理,比如说淘宝上的一个代理商,现有该代理商
  * 在网上接到客户的订单,然后他(她)再向销售商Vendor
  * 下单赚区差价
  * @author JackyChen
  *
  */
 public class VendorProxyHandler implements InvocationHandler {
	
	private Object objOriginal;
	
	public VendorProxyHandler(Object obj){
		this.objOriginal = obj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//可以在这里添加一些预处理操作,如权限控制等...
		Object result = method.invoke(this.objOriginal, args);
		//也可以在此处添加一些后置处理操作...
		return result;
	}

 }

 package org.pattern;

 import java.lang.reflect.Proxy;

 public class JDKDynamicProxyExample{
	
	   public static void main(String[] args){
		  //创建销售商
		  Vendor vendor = new Vendor();
		  //创建动态代理的处理器
		  VendorProxyHandler handler = new VendorProxyHandler(vendor);
		  //创建动态代理类
		  ISell proxyObj = (ISell)  Proxy.newProxyInstance(vendor.getClass().getClassLoader(), 
				Vendor.class.getInterfaces(), handler);
		  //卖货
		  proxyObj.sell();
	   }

 }
        


       
        CGLIB动态代理
        CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
        下面我们来看一下CGLIB动态代理中涉及的几个类:
         net.sf.cglib.proxy.Enhancer – 主要的增强类
         net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
         net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
        Object o = methodProxy.invokeSuper(proxy, args);
        我们在这里简单举例,首先要有一个被代理的类,该类不能是final类:
 package org.pattern;

 /**
  * 需要被代理的类(也就是父类),通过字节码技术创建这个类的子类,实现动态代理
  * @author JackyChen
  *
  */
 public class CglibVendor {

	    public void sell(){
		   System.out.println("今天,俺又卖了一件货品!");		
	    }
 } 
        

        接下来我们来实现代理类:
 package org.pattern;

 import java.lang.reflect.Method;
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;
 import net.sf.cglib.proxy.MethodProxy;

 /**
  * Cglib代理类
  * @author JackyChen
  *
  */
 public class CglibVendorProxy implements MethodInterceptor{
	
	   private Enhancer enhancer = new Enhancer();
	
	   public Object getProxy(Class clazz){
		   /设置需要创建子类的类
		   enhancer.setSuperclass(clazz);
		   enhancer.setCallback(this);
		   //通过字节码技术动态创建子类实例
		   return enhancer.create();
	   }

	   /**
	    * 拦截所有目标类方法的调用
	    * @param obj: 目标类的实例
	    * @param method: 目标类方法的反射对象
	    * @param args: 方法的动态入参
	    * @param proxy: 代理类实例
	    */
	   @Override
	   public Object intercept(Object obj, Method method, Object[] args,
			   MethodProxy proxy) throws Throwable {
		   //可以在这里添加一些预处理操作,如权限控制等...
		   //通过代理类调用父类中的方法
		   Object result = proxy.invokeSuper(obj, args);
		   //也可以在此处添加一些后置处理操作...
		   return result;
	   }

 }

        调用Cglib动态代理的示例:
 package org.pattern;

 public class CglibDynamicProxyExample {

	 public static void main(String[] args){
		 CglibVendorProxy proxy = new CglibVendorProxy();
		 //通过生成子类的方式创建代理类
		 CglibVendor proxyImp = (CglibVendor)proxy.getProxy(CglibVendor.class);
		 proxyImp.sell();
	 }
 }
        

        从上面的代码量上来看,Cglib动态代理要少很多,并且代码较为清晰而干净。在性能上:CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
  • 大小: 55 KB
分享到:
评论
1 楼 wisesean 2013-06-03  
好文章 一看就懂了

相关推荐

    设计模式:可复用面向对象软件的基础.zip

    设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。这些模式经过时间的考验,被广泛应用于各种面向对象的软件开发中,以提高代码的可读性、可维护性和可复用性。本教程旨在深入讲解...

    设计模式:可复用面向对象软件的基础(非扫描版+高清)

    设计模式分为三类:创建型模式(如单例模式、工厂方法模式)、结构型模式(如代理模式、装饰器模式)和行为型模式(如观察者模式、策略模式)。每种模式都有其特定的用途和适用场景。 4. **具体设计模式详解** - ...

    《设计模式:可复用面向对象软件的基础》英文版

    《设计模式:可复用面向对象软件的基础》是一本由Erich Gamma、Richard Helm等四位国际知名的软件工程师共同编写的经典之作,该书提供了面向对象软件设计中常用的模式,并通过具体的案例解释了这些模式如何帮助解决...

    设计模式:可复用面向对象软件的基础--详细书签版

     “[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法...

    Java设计模式——代理设计模式(静态代理和动态代理)

    代理设计模式分为静态代理和动态代理两种类型。 ### 静态代理 静态代理是在编译时就已经确定了代理关系,代理类和真实类的关系是硬编码在代理类中的。下面我们将详细介绍静态代理的实现方式: 1. **定义接口**:...

    java 设计模式之代理模式(Proxy Pattern)实现代码及设计详解:动态代理模式、静态代理模式

    Java设计模式是软件开发中的重要概念,它提供了一套通用的解决方案模板,使得代码更加可复用、可扩展。在这些模式中,代理模式(Proxy Pattern)是...对于Java开发者来说,掌握设计模式是提升专业技能的关键步骤之一。

    动态代理设计模式 日志和源码

    动态代理设计模式是一种在运行时创建代理对象的技术,它允许我们为现有的对象提供额外的功能,如日志记录、性能监控、事务管理等,而无需修改原对象的代码。这种模式在Java和许多其他编程语言中都有应用,尤其在...

    设计模式:可复用的面向对象软件的基础

    掌握设计模式对游戏引擎的开发尤其重要,因为游戏引擎通常需要处理复杂的系统交互和动态变化的游戏逻辑,设计模式提供了一种结构化和模块化的思路,使得开发者能够高效地处理这些问题。 面向对象的概念包括封装、...

    设计模式:可复用面向对象软件设计基础(附源码)

    设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。这些模式通过前人的经验总结,为开发人员提供了一种标准化的...所以,深入理解和熟练运用设计模式是每个专业程序员必备的技能之一。

    代理设计模式:静态代理和动态代理的理解、实现与区别(优缺点)与SpringAOP的3种配置方式案例工程代码

    本资源主要涵盖了静态代理和动态代理两种常见类型的代理模式,以及Spring AOP中动态代理的三种配置方式。以下是详细的知识点解析: ### 静态代理 静态代理是程序员手动创建代理类并实现相同接口的方式。代理类和...

    动态代理设计模式

    详细而又简单的讲述了java动态代理设计模式

    动态代理设计模式-源码

    动态代理设计模式是一种在运行时创建对象代理的技术,它允许我们为现有的对象提供额外的功能,而无需修改原对象的代码。这种模式的核心是接口和代理类,通过接口,代理类可以与原对象进行通信,同时在代理类中添加...

    动态代理设计模式详解.pdf

    动态代理设计模式是一种编程技术,它允许在运行时创建具有相同接口的新对象,该对象能够对原对象的行为进行增强或扩展。在这个模式中,代理对象作为客户端与目标对象之间的中介,代理可以添加额外的功能,如日志记录...

    设计模式之代理模式demo

    代理模式是一种常用的设计模式,它在软件开发中起到了中介或者代表的作用。代理模式的主要目的是为其他对象提供一种代理以控制对这个对象的访问。通过引入代理,我们可以增加新的功能,如缓存、日志记录、访问控制等...

    java静态代理、动态代理、装饰设计模式

    在Java编程中,代理模式是一种常见的设计模式,它允许我们为一个对象提供一个代理以控制对这个对象的访问。代理模式通常用于增加额外的功能或在访问原对象时进行额外的操作,比如日志记录、安全控制、性能统计等。...

    设计模式之代理模式proxy

    **设计模式之代理模式(Proxy Pattern)** 设计模式是软件工程中的一种最佳实践,它是在特定情境下解决常见问题的模板。代理模式是其中一种行为设计模式,它的核心思想是为一个对象提供一个替身或者代理,以控制对...

    设计模式-代理模式

    代理模式是一种常用的设计模式,它在软件开发中扮演着重要的角色,特别是在iOS平台的应用程序设计中。代理模式的核心思想是为一个对象提供一个替身或代理,以控制对这个对象的访问。这种模式允许我们通过代理来间接...

    设计模式:创建型之原型(深浅拷贝)、单例(饿汉式与懒汉式),三大工厂模式 结构型之适配器模式,代理模式(三大代理)

    代理模式具有多种实现形式,例如静态代理、动态代理和CGLib代理。代理模式可以隐藏真实对象的实现细节,便于扩展和维护,符合开闭原则,但可能会引入额外的复杂性。 设计模式的六大原则是设计模式遵循的基本规则,...

    设计模式之代理模式

    **设计模式之代理模式** 代理模式是软件设计模式中的一种结构型模式,它在对象交互过程中引入一个代理,代理对象负责控制对原对象的访问。这种模式的主要目的是为了解耦,提供一种替代真实对象的方式,使得客户端...

Global site tag (gtag.js) - Google Analytics