java代理模式--静态代理和动态代理
来源:互联网 发布:留学生落户北京 知乎 编辑:程序博客网 时间:2024/05/19 15:25
设计模式中的代理模式应用很广,网上这方面资料很多,客户端代码不想或不能够直接访问被调用对象时,代理对象可以在客户端和目标对象之间起到中介作用,常用的场景:
- 创建一个系统开销很大的对象(延迟创建或真正调用时再创建)
- 被调用对象在远程主机上
- 目标对象的功能还不足以满足需求(增强功能)
java很容易就可以实现代理模式,每一个代理类在编译之后都会生成一个class文件,代理类所实现的接口和所代理的方法都被固定,这种代理被称之为静态代理(Static Proxy)。那么有没有一种机制能够让系统在运行时动态创建代理类?从JDK 1.3开始,Java语言提供了对动态代理的支持。下面举例比较两种代理方式
一、静态代理
定义两个接口和对应的实现类
接口1:Account.java
package com.css.sword.proxy;public interface Account {public void query();public int sum();}
实现类:AccountImpl.java
package com.css.sword.proxy;public class AccountImpl implements Account { @Override public void query() { // TODO Auto-generated method stub System.out.println("开始查询账目……"); } @Override public int sum() { // TODO Auto-generated method stub System.out.println("开始合计……"); return 0; }}
接口2:Cook.java
package com.css.sword.proxy;public interface Cook {public void fire();public void cut();}
实现类:CookImpl.java
package com.css.sword.proxy;public class CookImpl implements Cook { @Override public void fire() { // TODO Auto-generated method stub System.out.println("开始加火……"); } @Override public void cut() { // TODO Auto-generated method stub System.out.println("开始切菜……"); }}
代理类:每个接口需创建一个代理类,注意代理类要实现一样的接口
AccountProxy.java
package com.css.sword.proxy;public class AccountProxy implements Account { private Account account; AccountProxy(Account account){ this.account=account; } @Override public void query() { // TODO Auto-generated method stub System.out.println("开始调用query方法"); account.query(); System.out.println("query方法调用结束"); } @Override public int sum() { // TODO Auto-generated method stub System.out.println("开始调用sum方法"); account.sum(); System.out.println("sum方法调用结束"); return 0; }}
CookProxy.java
package com.css.sword.proxy;public class CookProxy implements Cook { private Cook cook; CookProxy(Cook cook) { this.cook=cook; } @Override public void fire() { // TODO Auto-generated method stub System.out.println("开始调用fire方法"); cook.fire(); System.out.println("fire方法调用结束"); } @Override public void cut() { // TODO Auto-generated method stub System.out.println("开始调用cut方法"); cook.cut(); System.out.println("cut方法调用结束"); }}
测试类:TestStaticProxy.java
package com.css.sword.proxy;public class TestStaticProxy { public static void main(String[] args) { AccountProxy accountProxy = new AccountProxy(new AccountImpl()); accountProxy.query(); accountProxy.sum(); System.out.println("-------------------------------------------------"); CookProxy cookProxy = new CookProxy(new CookImpl()); cookProxy.fire(); cookProxy.cut(); }}
结果:
这里可以看到静态代理每个接口都需要一个代理类,如果需要每个方法在执行前和后加入的是相同的操作,代理类中每个方法都需要加入相同的代码,这样程序中就有太多重复的代码。动态代理可以有效解决这个问题。
二、动态代理
接口及实现类不变,动态代理只需一个代理类:
package com.css.sword.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class DynamicProxy implements InvocationHandler { private Object target; public Object getProxy(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 { // TODO Auto-generated method stub String methodName = method.getName(); System.out.println("开始调用"+methodName+"方法"); Object result = method.invoke(target, args); System.out.println(methodName+"方法调用结束"); return result; }}
测试结果:
动态代理类需实现InvocationHandler接口,并实现其invoke方法,每当通过Proxy.newProxyInstance(……)方法获得某个接口的代理并调用方法时,程序就会回调invoke(……)方法。这样就不用为每个接口配置一个代理类,也不用为每个方法填写相同的增强代码。这里也可以看到jdk本身实现的动态代理有个弊端,那就是只能为接口生成代理,如果一个类没有实现接口,又想生成其代理类有什么办法?cglib可以解决这个问题
三、cglib动态代理
要想使用cglib需要下载相关包,网上一般会提供两种包,例如下图:
起初我一直不知道该用哪个包,后来在查阅相关资料和对两个包做出的对比,得出以下结论(但不确定是否正确,如果有什么不对希望大家批评指正):
cglib底层是用asm框架来处理字节码,如果使用cglib-x.x.x.jar的话需要再下载asm相关包,而cglib-nodep-x.x.x.jar中已包含asm需要的相关类,就不需要再下载其它包。经过测试得出的结果也是这样的。单独引cglib包需要注意的cglib版本和asm版本。在测试过程中总是因为这两个包的版本不能匹配而报错,最终测试通过的版本是cglib-2.2.3和asm-all-4.0.jar
新建一个类(不实现接口):AccountService.java
package com.css.sword.proxy;public class AccountService { public void query() { // TODO Auto-generated method stub System.out.println("开始查询账目……"); } public int sum() { // TODO Auto-generated method stub System.out.println("开始合计……"); return 0; }}
代理类:CglibProxy.java
package com.css.sword.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor { private Object target; public Object getProxy(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 { // TODO Auto-generated method stub String methodName = method.getName(); System.out.println("开始调用"+methodName+"方法"); proxy.invokeSuper(obj, args); System.out.println(methodName+"方法调用结束"); return null; }}
测试类:TestCglibProxy.java
package com.css.sword.proxy;public class TestCglibProxy { public static void main(String[] args){ CglibProxy cProxy = new CglibProxy(); AccountService accountProxy = (AccountService) cProxy.getProxy(new AccountService()); accountProxy.query(); accountProxy.sum(); }}
测试结果:
- Java代理模式 静态代理 动态代理
- 代理模式--静态代理和动态代理
- Java中的代理模式----静态代理和动态代理
- java代理模式--静态代理和动态代理
- java的代理模式(动态代理和静态代理)
- java 代理模式 静态代理和动态代理
- 代理模式(静态代理和动态代理) JAVA
- Java代理模式 静态代理,动态代理,Cglib代理
- 静态代理模式和动态代理模式
- Java设计模式之—静态代理和动态代理
- java设计模式之静态代理和动态代理
- Java设计模式之 静态代理和动态代理
- java的代理模式(静态和动态代理)
- java设计模式-代理模式(静态代理,动态代理)
- 设计模式- 代理模式 (静态代理 和 动态代理)
- 设计模式之代理模式--静态代理和动态代理
- java 设计模式 代理 静态和动态
- java中的静态和动态代理模式
- 带有标签的流布局,,,实现标签的选中,添加和删除功能....
- JS之概述
- AFNetworking网络请求头的设定
- php 操作 redis
- Core Animation Part II: Layers “everywhere” 核心动画第二弹:俯拾皆"层"
- java代理模式--静态代理和动态代理
- mfc中避免闪烁的方法(OnEraseBkgnd)
- Apple Pay 应用内支付流程分析
- Zookeeper学习(一):Zookeeper的概述
- iOS开发-指纹登录(TouchID)集成方案——逻辑设计和实现
- NSString用法、Obj-C数组以及字符串拼接与分割
- Bootstrap一些例子使用,持续更新...
- windows server 2008 R2 挂载新磁盘空间
- 用VideoView实现视频的无缝连续播放