重温java代理模式

2024-05-15 03:48
文章标签 java 模式 代理 重温

本文主要是介绍重温java代理模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章关键词:java代理,jdk动态代理,cglib代理,AOP,切面编程

今天,逛技术博客时,无意间发现了一篇有关动态代理模式的文章,感觉写的不错,自己正好也在巩固下基础知识,虽然实际工作中用代理的模式的不是特别多,那是因为你使用的框架,已经帮你封装好了,所以,你可能感觉不到,但是感觉不到不但表不存在,了解下它的原理和使用场景还是能提高下逼格的。于是散仙总结了下文,还有一个实战小例子,用来帮助理解。下面开始:

一:什么是代理?
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

说白了,代理模式其实就相当于找房子时的中介,你无须找到真实的房东,就可以把租房子这件事给办了,而且因为中介,所以便有了一些额外增强的功能,所以少数中介会提高房价或黑你一下,当然咱们的程序肯定不是跟中介一个德行的。


二:java中代理的种类
(1)静态代理: 只能提供固定的类的代理,局限性比较大
(2)JDK动态代理:只能代理接口,通过反射,提高了灵活性,但性能稍慢
(3)CGLIB代理:Spring AOP的默认实现,可以代理类,无须提供对应接口,通过ASM(asm是Java字节码操控框架,ASM是一套java字节码生成架构,它可以动态生成二进制格式的stub类或其它代理类,或者在类被java虚拟机装入内存之前,动态修改类)字节码增强,速度要快于JDK的默认的动态代理。


三:使用代理的应用场景

这个问题,其实就跟问Spring AOP切面编程的好处,就非常类似了,通过代理模式,我们可以无侵入式的,很方便的实现日志记录功能,方法权限拦截功能,事务控制等功能。


四:实战例子
项目结构:




百度云盘下载: http://pan.baidu.com/s/1eQ0h5YE
1,JDK动态代理,模拟事务控制功能,已经记录方法的耗时功能 

Java代码 复制代码  收藏代码
  1. package com.easy.model;   
  2. /***  
  3.  *   
  4.  * @author qindongliang  
  5.  *  
  6.  */  
  7. public class Person {   
  8.        
  9.     //用户名   
  10.     private String name;   
  11.   
  12.     public String getName() {   
  13.         return name;   
  14.     }   
  15.   
  16.     public void setName(String name) {   
  17.         this.name = name;   
  18.     }   
  19.        
  20.        
  21.        
  22.     public Person(String name) {   
  23.         super();   
  24.         this.name = name;   
  25.     }   
  26.   
  27.     public Person() {   
  28.         // TODO Auto-generated constructor stub   
  29.     }   
  30.   
  31. }  
package com.easy.model;
/**** * @author qindongliang**/
public class Person {//用户名private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(String name) {super();this.name = name;}public Person() {// TODO Auto-generated constructor stub}}

Dao接口已经实现类,里面含有测试的方法:
Java代码 复制代码  收藏代码
  1. package com.easy.dao;   
  2.   
  3. import com.easy.model.Person;   
  4. /***  
  5.  * 动态代理测试dao  
  6.  * @author qindongliang  
  7.  *  
  8.  */  
  9. public interface PersonDao {   
  10.     //add user   
  11.     public void addUser(Person user);   
  12.     //delete user   
  13.     public void deleteUser(String name);   
  14.     //update user   
  15.     public void updateUser(String name);   
  16.   
  17. }  
package com.easy.dao;import com.easy.model.Person;
/**** 动态代理测试dao* @author qindongliang**/
public interface PersonDao {//add userpublic void addUser(Person user);//delete userpublic void deleteUser(String name);//update userpublic void updateUser(String name);}

实现类:
Java代码 复制代码  收藏代码
  1. package com.easy.dao.impl;   
  2.   
  3. import com.easy.dao.PersonDao;   
  4. import com.easy.model.Person;   
  5. /***  
  6.  * Dao的实现类  
  7.  * @author qindongliang  
  8.  *  
  9.  */  
  10. public class PersonDaoImpl implements PersonDao {   
  11.   
  12.     @Override  
  13.     public void addUser(Person user) {   
  14.         // TODO Auto-generated method stub   
  15. //      System.out.println("add user name: "+user.getName());   
  16.         try{   
  17.             Thread.sleep(1000);//sleep 1 second   
  18.         }catch(Exception e){   
  19.             e.printStackTrace();   
  20.         }   
  21.     }   
  22.   
  23.     @Override  
  24.     public void deleteUser(String name) {   
  25. //      System.out.println("delete user name: "+name);   
  26.         try{   
  27.             Thread.sleep(1500);//sleep 1.5 second   
  28.         }catch(Exception e){   
  29.             e.printStackTrace();   
  30.         }   
  31.            
  32.     }   
  33.   
  34.     @Override  
  35.     public void updateUser(String name) {   
  36. //      System.out.println("update user name: "+name);   
  37.         try{   
  38.             Thread.sleep(2000);//sleep 2 second   
  39.         }catch(Exception e){   
  40.             e.printStackTrace();   
  41.         }   
  42.     }   
  43.        
  44.   
  45. }  
package com.easy.dao.impl;import com.easy.dao.PersonDao;
import com.easy.model.Person;
/**** Dao的实现类* @author qindongliang**/
public class PersonDaoImpl implements PersonDao {@Overridepublic void addUser(Person user) {// TODO Auto-generated method stub
//		System.out.println("add user name: "+user.getName());try{Thread.sleep(1000);//sleep 1 second}catch(Exception e){e.printStackTrace();}}@Overridepublic void deleteUser(String name) {
//		System.out.println("delete user name: "+name);try{Thread.sleep(1500);//sleep 1.5 second}catch(Exception e){e.printStackTrace();}}@Overridepublic void updateUser(String name) {
//		System.out.println("update user name: "+name);try{Thread.sleep(2000);//sleep 2 second}catch(Exception e){e.printStackTrace();}}}

JDK动态代理实现:
Java代码 复制代码  收藏代码
  1. package com.easy.proxy;   
  2.   
  3. import java.lang.reflect.InvocationHandler;   
  4. import java.lang.reflect.Method;   
  5. import java.text.SimpleDateFormat;   
  6. import java.util.Date;   
  7. /***  
  8.  * JDK动态代理例子  
  9.  * @author qindongliang  
  10.  *  
  11.  */  
  12. public class JDK_Proxy implements InvocationHandler {   
  13.        
  14.     //代理实例   
  15.     private Object proxy;   
  16.     //通过构造参数赋值   
  17.     public JDK_Proxy(Object proxy) {   
  18.         this.proxy = proxy;   
  19.     }   
  20.   
  21.     //格式化时间   
  22.     private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");   
  23.        
  24.        
  25.   
  26.   
  27.   
  28.     @Override  
  29.     public Object invoke(Object proxy, Method method, Object[] args)   
  30.             throws Throwable {   
  31.         Object obj=null;   
  32.         //开始时间   
  33.         long start=System.currentTimeMillis();   
  34.         //以add开头的方法,加入事务控制   
  35.         if(method.getName().startsWith("add")){   
  36.             //开启事务   
  37.             startTransaction(method);   
  38.             obj=method.invoke(this.proxy, args);   
  39.             //关闭事务   
  40.             closeTransaction(method);   
  41.         }else{   
  42.             obj=method.invoke(this.proxy, args);   
  43.         }   
  44.            
  45.         //调用结束时间   
  46.         long end=System.currentTimeMillis();   
  47.         System.out.println(sdf.format(new Date())+"  "+method.getName()+"调用方法执行时间为:"+(end-start)/1000+"秒!");   
  48.         System.out.println();   
  49.         return obj;   
  50.     }   
  51.        
  52.     //模拟开启事务   
  53.     public void startTransaction(Method method){   
  54.         System.out.println("请注意:"+method.getName()+"开启了 commit 事务操作 !");   
  55.     }   
  56.        
  57.     //模拟关闭事务   
  58.     public void closeTransaction(Method method){   
  59.         System.out.println("请注意:"+method.getName()+"关闭了 commit 事务操作 !");   
  60.     }   
  61.        
  62.        
  63.        
  64.        
  65.        
  66.        
  67.        
  68.        
  69.   
  70. }  
package com.easy.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**** JDK动态代理例子* @author qindongliang**/
public class JDK_Proxy implements InvocationHandler {//代理实例private Object proxy;//通过构造参数赋值public JDK_Proxy(Object proxy) {this.proxy = proxy;}//格式化时间private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object obj=null;//开始时间long start=System.currentTimeMillis();//以add开头的方法,加入事务控制if(method.getName().startsWith("add")){//开启事务startTransaction(method);obj=method.invoke(this.proxy, args);//关闭事务closeTransaction(method);}else{obj=method.invoke(this.proxy, args);}//调用结束时间long end=System.currentTimeMillis();System.out.println(sdf.format(new Date())+"  "+method.getName()+"调用方法执行时间为:"+(end-start)/1000+"秒!");System.out.println();return obj;}//模拟开启事务public void startTransaction(Method method){System.out.println("请注意:"+method.getName()+"开启了 commit 事务操作 !");}//模拟关闭事务public void closeTransaction(Method method){System.out.println("请注意:"+method.getName()+"关闭了 commit 事务操作 !");}}

无接口的cglib代理测试类:
Java代码 复制代码  收藏代码
  1. package com.easy.dao.impl;   
  2.   
  3. /***  
  4.  * 此类没有实现任何接口,只能使用Cglib代理来调用方法  
  5.  * 必须有无参的构造方法  
  6.  * @author qindongliang  
  7.  *  
  8.  */  
  9. public class CarManager {   
  10.        
  11.     private String name;   
  12.        
  13.        
  14.     public CarManager() {   
  15.         // TODO Auto-generated constructor stub   
  16.     }   
  17.        
  18.     public CarManager(String name) {   
  19.         this.name = name;   
  20.     }   
  21.   
  22.   
  23.   
  24.     public String getName() {   
  25.         return name;   
  26.     }   
  27.   
  28.   
  29.   
  30.     public void setName(String name) {   
  31.         this.name = name;   
  32.     }   
  33.   
  34.   
  35.   
  36.     public void run()throws Exception{   
  37.         System.out.println(this.getName()+"汽车启动了!");   
  38.         Thread.sleep(3000);   
  39.     }   
  40.   
  41.        
  42.        
  43.     public void stop(){   
  44.         System.out.println(this.getName()+"汽车停止了!");   
  45.     }   
  46.        
  47.        
  48.        
  49.   
  50. }  
package com.easy.dao.impl;/**** 此类没有实现任何接口,只能使用Cglib代理来调用方法* 必须有无参的构造方法* @author qindongliang**/
public class CarManager {private String name;public CarManager() {// TODO Auto-generated constructor stub}public CarManager(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void run()throws Exception{System.out.println(this.getName()+"汽车启动了!");Thread.sleep(3000);}public void stop(){System.out.println(this.getName()+"汽车停止了!");}}

  Cglib代理的实现:
Java代码 复制代码  收藏代码
  1. package com.easy.proxy;   
  2.   
  3. import java.lang.reflect.Method;   
  4.   
  5. import net.sf.cglib.proxy.Enhancer;   
  6. import net.sf.cglib.proxy.MethodInterceptor;   
  7. import net.sf.cglib.proxy.MethodProxy;   
  8.   
  9. /***  
  10.  * Cglib代理测试  
  11.  * @author qindongliang  
  12.  */  
  13. public class CGLIB_Proxy implements MethodInterceptor{   
  14.   
  15.     //代理对象   
  16.     private Object target;   
  17.        
  18.        
  19.        
  20.      @SuppressWarnings("unchecked")     
  21.      public static <T> T proxyTarget(T t) {     
  22.             Enhancer en = new Enhancer();     
  23.             en.setSuperclass(t.getClass());     
  24.             en.setCallback(new CGLIB_Proxy(t));     
  25.             T tt = (T) en.create();     
  26.             return tt;     
  27.      }     
  28.        
  29.         
  30.     public CGLIB_Proxy(Object target) {   
  31.         this.target = target;   
  32.     }   
  33.   
  34.   
  35.   
  36.   
  37.   
  38.     @Override  
  39.     public Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable {   
  40.            
  41.         System.out.println("调用 "+method.getName()+" 开始......  ");   
  42.         //调用代理   
  43.         Object obj=method.invoke(this.target, args);   
  44.         System.out.println("调用 "+method.getName()+" 结束......  ");   
  45.         return obj;   
  46.     }   
  47.        
  48.        
  49.        
  50.        
  51.        
  52.        
  53.   
  54. }  
package com.easy.proxy;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 qindongliang*/
public class CGLIB_Proxy implements MethodInterceptor{//代理对象private Object target;@SuppressWarnings("unchecked")  public static <T> T proxyTarget(T t) {  Enhancer en = new Enhancer();  en.setSuperclass(t.getClass());  en.setCallback(new CGLIB_Proxy(t));  T tt = (T) en.create();  return tt;  }  public CGLIB_Proxy(Object target) {this.target = target;}@Overridepublic Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable {System.out.println("调用 "+method.getName()+" 开始......  ");//调用代理Object obj=method.invoke(this.target, args);System.out.println("调用 "+method.getName()+" 结束......  ");return obj;}}

测试的代码:
Java代码 复制代码  收藏代码
  1. package com.easy.main;   
  2.   
  3. import java.lang.reflect.InvocationHandler;   
  4. import java.lang.reflect.Proxy;   
  5.   
  6. import com.easy.dao.PersonDao;   
  7. import com.easy.dao.impl.CarManager;   
  8. import com.easy.dao.impl.PersonDaoImpl;   
  9. import com.easy.model.Person;   
  10. import com.easy.proxy.CGLIB_Proxy;   
  11. import com.easy.proxy.JDK_Proxy;   
  12.   
  13. /**  
  14.  * 包含jdk动态代理和cglib代理的测试  
  15.  * @author qindongliang  
  16.  *  
  17.  */  
  18. public class MethodTest {   
  19.        
  20.     public static void main(String[] args) throws Exception {   
  21.         //cglibProxyTest();   
  22.         jdkProxyTest();   
  23.     }   
  24.   
  25.        
  26.     /****  
  27.      * cglib代理测试  
  28.      */  
  29.     public static void cglibProxyTest()throws Exception{   
  30.            
  31.            
  32.         CarManager car=new CarManager("大众");   
  33. //         
  34. //      car.run();   
  35. //      car.stop();   
  36.         //得到代理类对象   
  37.         CarManager carManager=CGLIB_Proxy.proxyTarget(car);   
  38.         carManager.run();   
  39.            
  40.            
  41.            
  42.            
  43.            
  44.     }   
  45.        
  46.        
  47.     /***  
  48.      * jdk动态代理  
  49.      */  
  50.     public static void jdkProxyTest() {   
  51.         PersonDao user=new PersonDaoImpl();   
  52.            
  53.         Class<?> cls=user.getClass();   
  54.            
  55.         InvocationHandler handler=new JDK_Proxy(user);   
  56.            
  57.         //转换得来的代理对象   
  58.         PersonDao proxy=(PersonDao)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler);   
  59.            
  60.         proxy.addUser(new Person("hadoop"));   
  61.         proxy.deleteUser("lucene");   
  62.         proxy.updateUser("solr and elasticsearch");   
  63.     }   
  64.        
  65.        
  66.     
  67.        
  68.        
  69.   
  70. }  
package com.easy.main;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;import com.easy.dao.PersonDao;
import com.easy.dao.impl.CarManager;
import com.easy.dao.impl.PersonDaoImpl;
import com.easy.model.Person;
import com.easy.proxy.CGLIB_Proxy;
import com.easy.proxy.JDK_Proxy;/*** 包含jdk动态代理和cglib代理的测试* @author qindongliang**/
public class MethodTest {public static void main(String[] args) throws Exception {//cglibProxyTest();jdkProxyTest();}/***** cglib代理测试*/public static void cglibProxyTest()throws Exception{CarManager car=new CarManager("大众");
//		
//		car.run();
//		car.stop();//得到代理类对象CarManager carManager=CGLIB_Proxy.proxyTarget(car);carManager.run();}/**** jdk动态代理*/public static void jdkProxyTest() {PersonDao user=new PersonDaoImpl();Class<?> cls=user.getClass();InvocationHandler handler=new JDK_Proxy(user);//转换得来的代理对象PersonDao proxy=(PersonDao)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler);proxy.addUser(new Person("hadoop"));proxy.deleteUser("lucene");proxy.updateUser("solr and elasticsearch");}}



测试JDK动态代理结果:





测试cglib代理结果:



总结:使用代理模式,在一些场景,非常灵活,而且无侵入式的发挥巨大的作用,这就是面向切面编程的核心思想。



最后欢迎大家扫码关注微信公众号:我是攻城师(woshigcs),我们一起学习,进步和交流!(woshigcs)
本公众号的内容是有关搜索和大数据技术和互联网等方面内容的分享,也是一个温馨的技术互动交流的小家园,有什么问题随时都可以留言,欢迎大家来访!


参考文章:

http://andy136566.iteye.com/blog/967952
http://www.cnblogs.com/coderworld/p/java-reflect.html
http://blog.csdn.net/leon709/article/details/9529307
http://www.cnblogs.com/coderworld/p/java-dynamic-proxy.htm

这篇关于重温java代理模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990726

相关文章

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关