架构设计之设计模式 (二) 静态代理和动态代理--间接“美”
2013-07-22 00:51
471 查看
生活中有很多例子是间接来控制和访问的,比如你找一个人不自己亲自去,而是让别人代替去做这就是最简单的代理模式,是一种间接通信的例子,对象间的间接通信也同样是面向对象设计中的一条重要的“审美观”。间接通信可以让对象间耦合性降低,以及易于复用的架构设计。
间接控制对象的交互是一个重要的编程思想,有很多的模式都体现了这种思想,比如装饰模式、适配器模式、代理模式,都是通过间接的方式实现某一目的。
这里主要介绍一下代理模式,无论是在现实生活中还是计算机技术中用到代理的地方非常多,主要分为静态代理和动态代理。
我们都做过机房收费系统就那这个系统来举例子,这个系统中有对用户操作的用户接口IUser,以及实现了这个接口的类UserImp,Java代码如下。
用户实现类
在这个例子中,我们可能需要在添加用户或者删除用户的时候进行权限检查,符合权限的才能执行相关动作,否则不能执行,那么该如何修改代码才能更加贴切,而且在实际的编写过程中,虽然我们需要权限模块,但有时候为了更好地快速测试,我们常常希望暂时关闭权限模块,如何才能让这样的临时需求变得更加容易处理呢?我们现在使用代理模式来完成这样的任务,现在继续编写一个类叫 UserImplProxy.
用户代理类
这样就可以很容易的实现权限验证功能,很灵活。
但是问题又出现了,如果还有IStudent、ICard、IOnline……等很多接口,也许要同样的权限验证,是不是还要再为每一个接口都写一个代理类吗?
当然不是了,这个时候就需要用到动态代理了,动态代理模式可以在程序运行时为很多类做代理。
静态代理不足:一个被代理类对应一个代理类,当被代理类增多时,代理类会变多从而增加系统耦合度。
为了提高类的复用性和系统设计灵活性,使得代码更简洁,可以提取高层抽象类或接口。
Java提供了一个接口Java.lang.reflect.InvocationHandler和Proxy类支持动态代理,首先,介绍一下Proxy类,它有一个方法Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) ,这个方法返回一个代理类的对象。
ClassLoader loader:指定被代理对象的类加载器。
Class[] interfaces: 指定被代理对象所实现的接口。
InvocationHandler h:指定需要调用的InvocationHandler对象。
Java.lang.reflect.InvocationHandler接口,它只有一个方法invoke(),为代理类的抽象方法。有三个参数
Object proxy :代理类对象
Method method :被代理对象的方法
Object[] args :该方法的参数数组
JDK中实现原理
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2.将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中;
3.创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象。参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数。这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类所代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现。
我们增加ICard接口和Card类
Card实现类
动态代理类DynamicProxy
客户端测试类
运行结果为:
动态代理有点像多态一样,可以在程序运行时决定实例化哪一个对象,多态是利用接口向上转型来实现,觉得也可以用反射来实现,Java中的反射是一重要机制,是很多问题变得灵活,如果对反射原理比较熟悉,那么理解很多别的东西也会容易理解一些。
间接控制对象的交互是一个重要的编程思想,有很多的模式都体现了这种思想,比如装饰模式、适配器模式、代理模式,都是通过间接的方式实现某一目的。
这里主要介绍一下代理模式,无论是在现实生活中还是计算机技术中用到代理的地方非常多,主要分为静态代理和动态代理。
我们都做过机房收费系统就那这个系统来举例子,这个系统中有对用户操作的用户接口IUser,以及实现了这个接口的类UserImp,Java代码如下。
/** * 用户表接口 * @author LLS * */ public interface IUser { //添加用户 void addUser(); //删除用户 void delUser(); }
用户实现类
/** * 实现用户接口类 * @author LLS * */ public class UserImpl implements IUser { public void addUser() { // 添加用户代码 } public void delUser() { // 删除用户代码 } }
在这个例子中,我们可能需要在添加用户或者删除用户的时候进行权限检查,符合权限的才能执行相关动作,否则不能执行,那么该如何修改代码才能更加贴切,而且在实际的编写过程中,虽然我们需要权限模块,但有时候为了更好地快速测试,我们常常希望暂时关闭权限模块,如何才能让这样的临时需求变得更加容易处理呢?我们现在使用代理模式来完成这样的任务,现在继续编写一个类叫 UserImplProxy.
用户代理类
/** * 用户实现类的代理 * @author LLS * */ public class UserImplProxy implements IUser { //对用户实现类的引用 private UserImpl userImpl; //添加用户 public void addUser() { //调用添加之前进行权限验证 preIdentify(); if( userImpl == null ) { userImpl = new UserImpl(); } //调用源对象的添加 userImpl.addUser(); //添加完后,执行操作 postIdentify(); } public void delUser() { preIdentify(); if( userImpl == null ) { userImpl = new UserImpl(); } userImpl.addUser(); postIdentify(); } //验证方法 private void preIdentify() { System.out.println("添加之前验证代码!"); } //验证 private void postIdentify() { System.out.println("添加后执行操作"); } }
这样就可以很容易的实现权限验证功能,很灵活。
但是问题又出现了,如果还有IStudent、ICard、IOnline……等很多接口,也许要同样的权限验证,是不是还要再为每一个接口都写一个代理类吗?
当然不是了,这个时候就需要用到动态代理了,动态代理模式可以在程序运行时为很多类做代理。
静态代理不足:一个被代理类对应一个代理类,当被代理类增多时,代理类会变多从而增加系统耦合度。
为了提高类的复用性和系统设计灵活性,使得代码更简洁,可以提取高层抽象类或接口。
Java提供了一个接口Java.lang.reflect.InvocationHandler和Proxy类支持动态代理,首先,介绍一下Proxy类,它有一个方法Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) ,这个方法返回一个代理类的对象。
ClassLoader loader:指定被代理对象的类加载器。
Class[] interfaces: 指定被代理对象所实现的接口。
InvocationHandler h:指定需要调用的InvocationHandler对象。
Java.lang.reflect.InvocationHandler接口,它只有一个方法invoke(),为代理类的抽象方法。有三个参数
Object proxy :代理类对象
Method method :被代理对象的方法
Object[] args :该方法的参数数组
JDK中实现原理
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2.将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中;
3.创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象。参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数。这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类所代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现。
我们增加ICard接口和Card类
package com.proxy; /** * 卡接口 * @author LLS * */ public interface ICard { /** * 注册卡号 */ public void registerCard(); /** * 注销卡号 */ public void cancelCard(); }
Card实现类
package com.proxy; public class CardImpl implements ICard { @Override public void registerCard() { System.out.println("卡注册类"); } @Override public void cancelCard() { System.out.println("卡取消类"); } }
动态代理类DynamicProxy
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态生成代理类 * @author LLS * */ public class DynamicProxy implements InvocationHandler { /** * 对要代理对象的引用 */ private Object object=null; /** * 给引用复制 * @param object */ public DynamicProxy(Object object) { this.object=object; } /** * * @return */ public Object newProxyInstance(){ return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this); } /** * 通过代理对象,执行被代理对象的方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //进行权限验证 System.out.println("执行操作之前先进行权限验证,如果权限符合,则执行操作!"); Object res = method.invoke(object, args); return res; } }
客户端测试类
package com.proxy; /** * 客户端类 * @author LLS * */ public class Client { static public void main(String[] args) { //实例化被代理对象 UserImpl userImpl=new UserImpl(); //实例化一个产生代理对象的类 DynamicProxy dynamicProxyUser=new DynamicProxy(userImpl); //得到代理类对象 IUser proxyUser=(IUser)dynamicProxyUser.newProxyInstance(); //通过代理调用用户添加方法 proxyUser.addUser(); //同上 CardImpl cardImpl=new CardImpl(); DynamicProxy dynamicProxyCard=new DynamicProxy(cardImpl); ICard proxyCard=(ICard)dynamicProxyCard.newProxyInstance(); //通过代理调用,注册卡号方法 proxyCard.registerCard(); } }
运行结果为:
动态代理有点像多态一样,可以在程序运行时决定实例化哪一个对象,多态是利用接口向上转型来实现,觉得也可以用反射来实现,Java中的反射是一重要机制,是很多问题变得灵活,如果对反射原理比较熟悉,那么理解很多别的东西也会容易理解一些。
相关文章推荐
- 架构设计之设计模式 (二) 静态代理和动态代理--间接“美”
- Java设计模式之静态代理和动态代理(简单例子)
- java 设计模式之四-代理模式 java静态代理和动态代理
- 【GOF23设计模式】_代理模式_静态代理_动态代理_开发场景JAVA236-237
- Java设计模式学习06——静态代理与动态代理
- 设计模式—静态代理模式和动态代理模式(Proxy Pattern)
- Java 设计模式——静态代理模式和动态代理模式
- Spring 静态代理和动态代理设计模式
- Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理
- 代理设计模式之静态代理与动态代理(超..)详解
- java代理设计模式(静态代理与动态代理)
- 【设计模式之二:代理模式】代理模式(静态代理VS动态代理)
- java设计模式之静态代理与动态代理
- 设计模式- 代理模式 (静态代理 和 动态代理)
- Java设计模式——代理模式(静态代理vs动态代理)
- 系统架构设计——设计模式之代理模式(二)CGLIB动态代理实现
- java设计模式-代理模式(静态代理,动态代理)
- 代理设计模式之动态代理与静态代理
- 设计模式——代理模式(理解静态代理和动态代理+代码)
- java设计模式之代理模式 (静态&动态)