当前位置: 首页 > news >正文

java动态代理(JDK和cglib)

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

 

静态代理: 
Count.java 

 1 /** 
 2  * 定义一个账户接口 
 3  *  
 4  * @author Administrator 
 5  *  
 6  */  
 7 public interface Count {  
 8     // 查看账户方法  
 9     public void queryCount();  
10   
11     // 修改账户方法  
12     public void updateCount();  
13   
14 }  

 

CountImpl.java 

 1 /** 
 2  * 委托类(包含业务逻辑) 
 3  *  
 4  * @author Administrator 
 5  *  
 6  */  
 7 public class CountImpl implements Count {  
 8   
 9     @Override  
10     public void queryCount() {  
11         System.out.println("查看账户方法...");  
12   
13     }  
14   
15     @Override  
16     public void updateCount() {  
17         System.out.println("修改账户方法...");  
18   
19     }  
20   
21 }  

 

CountProxy.java  

 1 /** 
 2  * 这是一个代理类(增强CountImpl实现类) 
 3  *  
 4  * @author Administrator 
 5  *  
 6  */  
 7 public class CountProxy implements Count {  
 8     private CountImpl countImpl;  
 9   
10     /** 
11      * 覆盖默认构造器 
12      *  
13      * @param countImpl 
14      */  
15     public CountProxy(CountImpl countImpl) {  
16         this.countImpl = countImpl;  
17     }  
18   
19     @Override  
20     public void queryCount() {  
21         System.out.println("事务处理之前");  
22         // 调用委托类的方法;  
23         countImpl.queryCount();  
24         System.out.println("事务处理之后");  
25     }  
26   
27     @Override  
28     public void updateCount() {  
29         System.out.println("事务处理之前");  
30         // 调用委托类的方法;  
31         countImpl.updateCount();  
32         System.out.println("事务处理之后");  
33   
34     }  
35   
36 }  

 

TestCount.java 

 1 /** 
 2  *测试Count类 
 3  *  
 4  * @author Administrator 
 5  *  
 6  */  
 7 public class TestCount {  
 8     public static void main(String[] args) {  
 9         CountImpl countImpl = new CountImpl();  
10         CountProxy countProxy = new CountProxy(countImpl);  
11         countProxy.updateCount();  
12         countProxy.queryCount();  
13   
14     }  
15 }  

 

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

动态代理示例: 
BookFacade.java 

1 public interface BookFacade {  
2     public void addBook();  
3 } 

 

BookFacadeImpl.java 

1 public class BookFacadeImpl implements BookFacade {  
2   
3     @Override  
4     public void addBook() {  
5         System.out.println("增加图书方法。。。");  
6     }  
7   
8 }  

 

BookFacadeProxy.java  

 1 /** 
 2  * JDK动态代理代理类 
 3  *  
 4  * @author student 
 5  *  
 6  */  
 7 public class BookFacadeProxy implements InvocationHandler {  
 8     private Object target;  
 9     /** 
10      * 绑定委托对象并返回一个代理类 
11      * @param target 
12      * @return 
13      */  
14     public Object bind(Object target) {  
15         this.target = target;  
16         //取得代理对象  
17         return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
18                 target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
19     }  
20   
21     @Override  
22     /** 
23      * 调用方法 
24      */  
25     public Object invoke(Object proxy, Method method, Object[] args)  
26             throws Throwable {  
27         Object result=null;  
28         System.out.println("事物开始");  
29         //执行方法  
30         result=method.invoke(target, args);  
31         System.out.println("事物结束");  
32         return result;  
33     }  
34   
35 }  

 

TestProxy.java 

1 public class TestProxy {  
2   
3     public static void main(String[] args) {  
4         BookFacadeProxy proxy = new BookFacadeProxy();  
5         BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
6         bookProxy.addBook();  
7     }  
8   
9 } 

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

 

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,

并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
示例 :
BookFacadeCglib.java 

1 public interface BookFacade {  
2     public void addBook();  
3 } 

 

BookCadeImpl1.java 

 1 /** 
 2  * 这个是没有实现接口的实现类 
 3  *  
 4  * @author student 
 5  *  
 6  */  
 7 public class BookFacadeImpl1 {  
 8     public void addBook() {  
 9         System.out.println("增加图书的普通方法...");  
10     }  
11 }  

 

BookFacadeProxy.java 

 1 /** 
 2  * 使用cglib动态代理 
 3  *  
 4  * @author student 
 5  *  
 6  */  
 7 public class BookFacadeCglib implements MethodInterceptor {  
 8     private Object target;  
 9   
10     /** 
11      * 创建代理对象 
12      *  
13      * @param target 
14      * @return 
15      */  
16     public Object getInstance(Object target) {  
17         this.target = target;  
18         Enhancer enhancer = new Enhancer();  
19         enhancer.setSuperclass(this.target.getClass());  
20         // 回调方法  
21         enhancer.setCallback(this);  
22         // 创建代理对象  
23         return enhancer.create();  
24     }  
25   
26     @Override  
27     // 回调方法  
28     public Object intercept(Object obj, Method method, Object[] args,  
29             MethodProxy proxy) throws Throwable {  
30         System.out.println("事物开始");  
31         proxy.invokeSuper(obj, args);  
32         System.out.println("事物结束");  
33         return null;  
34   
35   
36     }  
37   
38 }  

 

TestCglib.java 

1 public class TestCglib {  
2       
3     public static void main(String[] args) {  
4         BookFacadeCglib cglib=new BookFacadeCglib();  
5         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
6         bookCglib.addBook();  
7     }  
8 }  

 

转载于:https://www.cnblogs.com/link1988/p/5508323.html

相关文章:

  • 巧用年线抓长线牛股的四种经典技巧
  • 说说spring注解
  • 爬虫入门(四)
  • CSS3D效果
  • 诈欺猎物160万+,同盾科技、猛犸等诈欺猎人们的反击战
  • µWebSockets:一种WebSocket服务器实现
  • 瞬间移动(组合数, 逆元)
  • Vue性能优化:如何实现延迟加载和代码拆分?
  • Guava - 并行编程Futures
  • Mybatis Generator逆向工程的使用
  • springMvc REST 请求和响应
  • 数字水印技术的研究现状与发展趋势
  • 简单登录系统
  • warning no match for this type name:xxx.xxx.xxx [Xlint:invalidAbsoluteTypeName]
  • 用UltraISO制作系统安装u盘
  • 【Amaple教程】5. 插件
  • CSS居中完全指南——构建CSS居中决策树
  • github指令
  • jquery ajax学习笔记
  • Map集合、散列表、红黑树介绍
  • nginx 配置多 域名 + 多 https
  • node入门
  • Redux系列x:源码分析
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 回顾2016
  • 深度学习中的信息论知识详解
  • 深入浅出Node.js
  • 小李飞刀:SQL题目刷起来!
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • (2)STL算法之元素计数
  • (rabbitmq的高级特性)消息可靠性
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (转)我也是一只IT小小鸟
  • ./configure、make、make install 命令
  • .net core 依赖注入的基本用发
  • .NET Core跨平台微服务学习资源
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .Net Core与存储过程(一)
  • .Net MVC + EF搭建学生管理系统
  • .NET连接数据库方式
  • @Valid和@NotNull字段校验使用
  • [20170713] 无法访问SQL Server
  • [AIGC] MySQL存储引擎详解
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • [APIO2015]巴厘岛的雕塑
  • [BJDCTF2020]The mystery of ip1
  • [C#]winform部署yolov5-onnx模型
  • [cocos creator]EditBox,editing-return事件,清空输入框