JAVA动态代理(JDK和CGLIB)

JAVA的动态代理 
代理模式 
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
按照代理的创建时期,代理类可以分为两种。 
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。 

 

首先看一下静态代理: 
1、Count.java 

package net.battier.dao;  /** * 定义一个账户接口 *  * @author Administrator *  */  
public interface Count {  // 查看账户方法  public void queryCount();  // 修改账户方法  public void updateCount();  }  

  


2、CountImpl.java 

package net.battier.dao.impl;  import net.battier.dao.Count;  /** * 委托类(包含业务逻辑) *  * @author Administrator *  */  
public class CountImpl implements Count {  @Override  public void queryCount() {  System.out.println("查看账户方法...");  }  @Override  public void updateCount() {  System.out.println("修改账户方法...");  }  }  、CountProxy.java  
package net.battier.dao.impl;  import net.battier.dao.Count;  /** * 这是一个代理类(增强CountImpl实现类) *  * @author Administrator *  */  
public class CountProxy implements Count {  private CountImpl countImpl;  /** * 覆盖默认构造器 *  * @param countImpl */  public CountProxy(CountImpl countImpl) {  this.countImpl = countImpl;  }  @Override  public void queryCount() {  System.out.println("事务处理之前");  // 调用委托类的方法;  countImpl.queryCount();  System.out.println("事务处理之后");  }  @Override  public void updateCount() {  System.out.println("事务处理之前");  // 调用委托类的方法;  countImpl.updateCount();  System.out.println("事务处理之后");  }  }  

  

 

3、TestCount.java 

package net.battier.test;  import net.battier.dao.impl.CountImpl;  
import net.battier.dao.impl.CountProxy;  /** *测试Count类 *  * @author Administrator *  */  
public class TestCount {  public static void main(String[] args) {  CountImpl countImpl = new CountImpl();  CountProxy countProxy = new CountProxy(countImpl);  countProxy.updateCount();  countProxy.queryCount();  }  
}  

  

 

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 
再来看一下动态代理: 
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接口的子类实例 

Ps:类加载器 
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; 
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

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

动态代理示例: 
1、BookFacade.java 

package net.battier.dao;  public interface BookFacade {  public void addBook();  
}  

  

 

2、BookFacadeImpl.java 

package net.battier.dao.impl;  import net.battier.dao.BookFacade;  public class BookFacadeImpl implements BookFacade {  @Override  public void addBook() {  System.out.println("增加图书方法。。。");  }  }  、BookFacadeProxy.java  package net.battier.proxy;  import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  /** * JDK动态代理代理类 *  * @author student *  */  
public class BookFacadeProxy 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;  }  }  

  

 

3、TestProxy.java 

package net.battier.test;  import net.battier.dao.BookFacade;  
import net.battier.dao.impl.BookFacadeImpl;  
import net.battier.proxy.BookFacadeProxy;  public class TestProxy {  public static void main(String[] args) {  BookFacadeProxy proxy = new BookFacadeProxy();  BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  bookProxy.addBook();  }  }  

  

 

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

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

package net.battier.dao;  public interface BookFacade {  public void addBook();  
}  

  

 

2、BookCadeImpl1.java 

package net.battier.dao.impl;  /** * 这个是没有实现接口的实现类 *  * @author student *  */  
public class BookFacadeImpl1 {  public void addBook() {  System.out.println("增加图书的普通方法...");  }  
}  

  


3、BookFacadeProxy.java 

package net.battier.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 student *  */  
public class BookFacadeCglib 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;  }  
}  

  


4、TestCglib.java 

package net.battier.test;  import net.battier.dao.impl.BookFacadeImpl1;  
import net.battier.proxy.BookFacadeCglib;  public class TestCglib {  public static void main(String[] args) {  BookFacadeCglib cglib=new BookFacadeCglib();  BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  bookCglib.addBook();  }  
}  

  

转载于:https://www.cnblogs.com/deepbreath/p/4138982.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/492712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

duilib消息机制的介绍

参考&#xff1a;https://www.cnblogs.com/redrainblog/p/4209721.html

徐铁:当深度学习握手脑科学-圣城会议归来

原创&#xff1a;许铁 来源&#xff1a;混沌巡洋舰耶路撒冷号称三教圣地&#xff0c; 而它的牛逼之处绝不仅在于宗教&#xff0c; 如果你深入了解&#xff0c; 你会发现它的科学&#xff0c;尤其是理论创新也同样牛逼&#xff0c; 尤其是在脑科学和人工智能方向。 当然神族…

hdu 1241Oil Deposits(BFS)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1241 Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13137 Accepted Submission(s): 7611 Problem DescriptionThe GeoSurvComp…

重磅!联合国权威AI趋势报告,美中日韩四分天下

来源&#xff1a;智东西摘要&#xff1a;AI趋势报告&#xff0c;中美专利申请和科学出版数遥遥领先。近年来&#xff0c;随着AI从理论知识落地到全球市场&#xff0c;AI正以其潜在的革命性影响&#xff0c;持续推动技术和产业的重大变革&#xff0c;从天气预报、自动驾驶、癌症…

模态窗口和非模态窗口

转载自&#xff1a;https://my.oschina.net/u/2425942/blog/882879 模态窗口就是在该窗口关闭之前&#xff0c;其父窗口不可能成为活动窗口的那种窗口。 例如&#xff1a; 窗口A弹出窗口B,如果窗口B是模态的&#xff0c;在窗口B关闭前就不可能切换到窗口A;如果B是非模态的&…

cut命令详解(转)

线上会log回归&#xff0c;计算请求超时率&#xff0c;会用到cut命令&#xff0c;看了一篇不错的文章&#xff0c;转了。。 1 描述一下cut命令 正如其名&#xff0c;cut的工作就是“剪”&#xff0c;具体的说就是在文件中负责剪切数据用的。 cut是以每一行为一个处理对象的&…

通信产业5G迭代,万亿机遇一触即发

来源&#xff1a;中银国际摘要&#xff1a;进入本世纪一零年代后&#xff0c;全球通信行业首先迎来了4G商用的元年。▌通信产业5G迭代促使中国企业突破进入本世纪一零年代后&#xff0c;全球通信行业首先迎来了4G商用的元年。LTE网络在世界各地开花&#xff0c;“管”领域的性能…

duilib中的添加自定义控件

原理参考博客&#xff1a;https://blog.csdn.net/zhuhongshu/article/details/45362751#commentBox 添加自定义的控件时&#xff0c;让程序识别该控件&#xff0c;要继承IDialogBuilderCallback接口&#xff0c;并实现接口中的CreateControl函数&#xff0c;自定义控件主要是继…

duilib中界面的布局方式

参考博客&#xff1a;https://blog.csdn.net/zhuhongshu/article/details/38531447 常用的布局默认为相对布局&#xff0c;默认floatfalse&#xff0c;该属性为true时&#xff0c;表示绝对布局&#xff1b; 相对布局方式可以依据界面自动调整控件大小。 最常用的VerticalLayout…

『重构--改善既有代码的设计』读书笔记----Split Temporary Variable

继续开始我们重构手法的系列&#xff0c;今天介绍的是Split Temporary Variable---分解临时变量。 在我们平常写的程序中肯定有某些临时变量被赋予了超过一个的责任。如果他们不是那种收集结果&#xff08;temp temp QString("abc")&#xff09;或者循环变量&#…

美丽新世界:这七个原因将让未来更美好

来源&#xff1a;资本实验室摘要&#xff1a;技术进步推动人类社会的进步。然而在现实生活中&#xff0c;对技术的恐惧困扰着相当一部分人。暴走的机器人、失控的AI、滥用的人体增强……这些经常出现于各种反乌托邦科幻故事中的场景也被认为是对技术破坏的一种警示。如果能够从…

学习OpenStack之 (4): Linux 磁盘、分区、挂载、逻辑卷管理 (Logical Volume Manager)

0. 背景&#xff1a; inux用户安装Linux操作系统时遇到的一个常见的难以决定的问题就是如何正确地评估各分区大小&#xff0c;以分配合适的硬盘空间。普通的磁盘分区管理方式在逻辑分区划分好之后就无法改变其大小&#xff0c;当一个逻辑分区存放不下某个文件时&#xff0c;这个…

写论文文献引用方式

打开百度学术&#xff1a; 如下&#xff1a;

美国DARPA204页可解释人工智能文献综述论文《Explanation in Human-AI Systems》

来源&#xff1a;专知摘要&#xff1a;本文介绍Arxiv上的《Explanation in Human-AI Systems》&#xff0c;一篇关于可解释机器学习的综述&#xff0c;介绍了可解释机器学习的多学科观点、历史研究、模型、关键点等。可解释AI是现在正火热的科研和工程问题。Arxiv上一篇《Expla…

Thinkphp系统常量

预定义常量 常量说明URL_COMMON0普通模式 URLURL_PATHINFO1PATHINFO URLURL_REWRITE2REWRITE URLURL_COMPAT3兼容模式 URLHAS_ONE1HAS_ONE 关联定义BELONGS_TO2BELONGS_TO 关联定义HAS_MANY3HAS_MANY 关联定义MANY_TO_MANY4MANY_TO_MANY 关联定义THINK_VERSION框架版本号这些预…

显卡的显存

首先说明&#xff0c;转载自&#xff1a;百度知道&#xff0c;作者&#xff1a;asdf_12346 网址&#xff1a;https://zhidao.baidu.com/question/216504146.html 千万注意不要只看显存大小了&#xff0c;显存大小只是影响显卡性能的一个很次要的因素而已。不了解的人很容易被商…

BestCoder22 1003.NPY and shot 解题报告

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid5144 题目意思&#xff1a;有个人抛物体&#xff0c;已知抛的速度和高度&#xff0c;问可以抛到的最远距离是多少。即水平距离。 做的时候是抄公式的&#xff0c;居然过了&#xff0c;幸运幸运............ 1 #…

37页PPT,全面解读5G产业链及未来趋势!

来源&#xff1a;国信证券经济研究所、全球物联网观察摘要&#xff1a;接下来的一年&#xff0c;5G无疑是全球关注的焦点。接下来的一年&#xff0c;5G无疑是全球关注的焦点。5G开始商用化&#xff0c;除了进一步促进移动互联网的发展&#xff0c;更重要的是会促进移动互联网和…

C++二级指针

如果动态分配一个2维数组&#xff0c;3行4列&#xff0c; int **map new int*[3]; for (int i 0; i < 3; i) {*(map i) new int[4]; }当这样写是动态申请的内存&#xff0c;内存空间为如下所示。可以看出动态申请的二维数组中内存不是连续的&#xff0c; for (int i …

atoi简析

原文链接 atoi()函数的功能&#xff1a;将字符串转换成整型数&#xff1b;atoi()会扫描参数nptr字符串&#xff0c;跳过前面的空格字符&#xff0c;直到遇上数字或正负号才开始做转换&#xff0c;而再遇到非数字或字符串时&#xff08;\0&#xff09;才结束转化&#xff0c;并将…