当前位置:首页 > CN2资讯 > 正文内容

Java动态代理学习2——静态代理和动态代理

18小时前CN2资讯

一、代理模式


代理模式是常用的java设计模式,特征是代理类委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。  

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

静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 
动态代理:在程序运行时运用反射机制动态创建而成。

 

二、静态代理

 

  • public interface CountDao  
  • {  
  •     // 查看账户方法  
  •     public void queryCount();  
  •  
  •     // 修改账户方法  
  •     public void updateCount();  
  •  
  • }  
  •  
  • public class CountDaoImpl implements CountDao  
  • {  
  •     public void queryCount()  
  •     {  
  •         System.out.println("查看账户方法...");  
  •     }  
  •  
  •     public void updateCount()  
  •     {  
  •         System.out.println("修改账户方法...");  
  •     }  
  • }  
  •  
  • public class CountProxy implements CountDao  
  • {  
  •     private CountDao countDao;  
  •  
  •     public CountProxy(CountDao countDao)  
  •     {  
  •         this.countDao = countDao;  
  •     }  
  •  
  •     @Override 
  •     public void queryCount()  
  •     {  
  •         System.out.println("事务处理之前");  
  •         countDao.queryCount();  
  •         System.out.println("事务处理之后");  
  •     }  
  •  
  •     @Override 
  •     public void updateCount()  
  •     {  
  •         System.out.println("事务处理之前");  
  •         countDao.updateCount();  
  •         System.out.println("事务处理之后");  
  •     }  
  • }  
  •  
  • public class TestCount  
  • {  
  •     public static void main(String[] args)  
  •     {  
  •         CountProxy countProxy = new CountProxy(new CountDaoImpl());  
  •         countProxy.updateCount();  
  •         countProxy.queryCount();  
  •     }  
  • }  
  • 观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 


     

    三、动态代理

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

     

    1 JDK动态代理

    JDK动态代理中包含一个类和一个接口

    InvocationHandler接口

     

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

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

     

    Proxy类

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

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

  • public interface PersonService  
  • {  
  •     public void save();  
  • }  
  •  
  • public class PersonServiceImpl implements PersonService  
  • {  
  •     public void save()  
  •     {  
  •         System.out.println("人员增加");  
  •     }  
  • }  
  •  
  • import java.lang.reflect.InvocationHandler;  
  • import java.lang.reflect.Method;  
  • import java.lang.reflect.Proxy;  
  •  
  • public class PersonProxy implements InvocationHandler  
  • {  
  •     // 目标对象  
  •     private Object target;  
  •  
  •     // 返回一个代理类对象  
  •     public Object createProxyInstance(Object target)  
  •     {  
  •         this.target = target;  
  •         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);  
  •     }  
  •  
  •     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  •     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  •     {  
  •         Object result = null;  
  •         System.out.println("前置通知");  
  •         try 
  •         {     
  •             result = method.invoke(target, args);  
  •             System.out.println("后置通知");  
  •         }  
  •         catch(Exception e)  
  •         {  
  •             System.out.println("例外通知——出错啦");  
  •         }  
  •         finally 
  •         {  
  •             System.out.println("最终通知——结束啦");   
  •         }  
  •         return result;  
  •     }  
  • }  
  •  
  • public class TestProxy  
  • {  
  •     public static void main(String[] args)  
  •     {  
  •         PersonProxy bp = new PersonProxy();  
  •         PersonService ps = (PersonService)bp.createProxyInstance(new PersonServiceImpl());  
  •         ps.save();  
  •     }  
  • 前置通知
    人员增加
    后置通知
    最终通知——结束啦

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

     

    2 CGLIB动态代理

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承所以不能对final修饰的类进行代理。

  • public interface PersonService  
  • {  
  •     public void save();  
  • }  
  •  
  • public class PersonServiceImpl implements PersonService  
  • {  
  •     public void save()  
  •     {  
  •         System.out.println("人员增加");  
  •     }  
  • }  
  •  
  • import java.lang.reflect.InvocationHandler;  
  • import java.lang.reflect.Method;  
  • import java.lang.reflect.Proxy;  
  •  
  • /**  
  •  * 使用CGLIB动态代理  
  •  */ 
  • public class PersonProxy implements MethodInterceptor  
  • {  
  •     private Object target;  
  •  
  •     // 返回一个代理类对象  
  •     public Object createProxyInstance(Object target)  
  •     {  
  •         this.target = target;  
  •         Enhancer enhancer = new Enhancer();  
  •  
  •         // 设置目标类为父类,会覆盖目标类的非final方法  
  •         enhancer.setSuperclass(this.target.getClass());  
  •  
  •         // 回调方法  
  •         enhancer.setCallback(this);  
  •  
  •         // 创建代理对象  
  •         return enhancer.create();  
  •     }  
  •  
  •     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  •     // 方法一  
  •     @Override 
  •     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  •     {  
  •         Object result = null;  
  •         System.out.println("前置通知");  
  •         try 
  •         { 
  •             result = method.invoke(target, args);  
  •             System.out.println("后置通知");  
  •         }  
  •         catch (Exception e)  
  •         {  
  •             System.out.println("例外通知——出错啦");  
  •         }  
  •         finally 
  •         {  
  •             System.out.println("最终通知——结束啦");  
  •         }  
  •         return result;  
  •     }  
  • }  
  •  
  • public class PersonProxy2 implements MethodInterceptor  
  • {  
  •     private Object target;  
  •  
  •     // 返回一个代理类对象  
  •     public Object createProxyInstance(Object target)  
  •     {  
  •         this.target = target;  
  •         Enhancer enhancer = new Enhancer();  
  •  
  •         // 设置目标类为父类,会覆盖目标类的非final方法  
  •         enhancer.setSuperclass(this.target.getClass());  
  •  
  •         // 回调方法  
  •         enhancer.setCallback(this);  
  •  
  •         // 创建代理对象  
  •         return enhancer.create();  
  •     }  
  •       
  •     // 方法二  
  •     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  •     {  
  •         Object result = null;  
  •         System.out.println("前置通知");  
  •         try 
  •         {   
  •             result = proxy.invokeSuper(obj, args);  
  •             System.out.println("后置通知");  
  •         }  
  •         catch (Exception e)  
  •         {  
  •             System.out.println("例外通知——出错啦");  
  •         }  
  •         finally 
  •         {  
  •             System.out.println("最终通知——结束啦");    
  •         }  
  •         return result;  
  •     }  
  • }  
  •  
  • public class TestProxy  
  • {  
  •     public static void main(String[] args)  
  •     {  
  •         PersonProxy cglib = new PersonProxy();  
  •         PersonServiceClass ps1 = (PersonServiceClass) cglib.createProxyInstance(new PersonServiceClass());  
  •         ps1.save();  
  •         System.out.println("--------------------");  
  •         PersonProxy2 cglib2 = new PersonProxy2();  
  •         PersonServiceClass ps2 = (PersonServiceClass) cglib2.createProxyInstance(new PersonServiceClass());  
  •         ps2.save();  
  •     }  
  • 前置通知
    增加人员
    后置通知
    最终通知——结束啦
    --------------------
    前置通知
    增加人员
    后置通知
    最终通知——结束啦
     

    参考并演绎自地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

      你可能想看:

      扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/24040.html

      分享给朋友:

      “Java动态代理学习2——静态代理和动态代理” 的相关文章

      香港虚拟主机CN2是什么意思?全面解析它的优势与意义

      权威解析香港虚拟主机CN2是什么在互联网飞速发展的今天,服务器托管和虚拟主机服务已经成为企业及个人站长运营网站必不可缺的一部分。面对市场上琳琅满目的虚拟主机类型,许多人对“香港虚拟主机CN2”这一概念感到困惑。什么是香港虚拟主机CN2?它到底有什么特殊之处?我们需要明确什么是虚拟主机。虚拟主机是指将...

      cn2排列公式怎么展开?原来排列组合还可以这么学!

      排列组合作为数学中一个重要的分支,在日常生活和实际问题中都有着广泛的应用。无论是计算概率、解决实际问题,还是在统计学中分析数据,排列组合都是不可或缺的工具。而在排列组合的核心公式中,C(n,2)是一个非常基础但又极其重要的公式。C(n,2)排列公式到底怎么展开?它背后又有哪些深层次的数学原理呢?让我...

      如何通过AWS CDN提升网站性能与安全性?全面解析Amazon CloudFront

      什么是AWS CDN AWS CDN,也就是Amazon CloudFront,是一个全球性的内容分发网络服务。它通过遍布全球的节点网络,确保内容能够快速、安全地传递给用户。无论是静态网页、动态内容,还是流媒体,AWS CDN都能提供高效的分发服务。它的设计目标是通过减少延迟和提高数据传输速度,提升...

      VPS流媒体解锁测试:确保顺畅访问全球流媒体内容

      在如今的互联网时代,流媒体已经成为我们日常生活中不可或缺的一部分。无论是观看热门电视剧,还是播放最新的音乐视频,流媒体服务的便捷性吸引了无数用户。然而,涉及不同地区提供的内容时,依然存在一些区域限制。这时,VPS(虚拟专用服务器)流媒体解锁技术的重要性便不言而喻。 VPS流媒体解锁是指通过虚拟专用服...

      探索韩国VPS服务:选择高性能低延迟的虚拟专用服务器

      在数字化迅猛发展的今天,韩国的VPS(虚拟专用服务器)越来越受到用户的青睐。许多企业和个人用户都开始关注这个区域,特别是那些需要稳定网站和应用程序的人。这篇文章将为你深入探讨韩国VPS的市场需求和背景,以及它在不同场景中的适用性。 首先,韩国VPS市场的兴起与其优越的网络基础设施密不可分。韩国位于东...

      狗云服务器怎么样?性能、服务与性价比全面解析

      狗云服务器(DogYun)自2019年成立以来,逐渐在国内云服务市场上崭露头角。最初的时候,我也只是偶然听说了这个名字,当时在寻找性能稳定又价格合理的云服务供应商时,恰好遇到了狗云。他们承诺提供高性价比的项目,这让我对他们充满了好奇。经过一番了解,发现狗云不仅仅是个新兴品牌,而是通过自身的技术积累和...