设计模式之动态代理模式
2014-10-19 18:48
351 查看
java的动态代理代理模式:为其他对象提供一种代理,并以控制对这个对象的访问。其特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等.
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
代理分为两种:静态代理和动态代理。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在。
动态代理:在程序运行时,利用java的反射机制动态创建而成。
动态代理原理
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
利用JDK的动态代理写一个小Demo.
先一个Hello.java接口
再写这个接口的实现HelloImpl.java
最后写一个测试类LogTest.java
输出的结果为:
其实我们可以自己来模拟一个动态代理类来实现相应的功能。
问题描述:为Tank类的move()函数做一个时间日志管理。
1.先写一个Moveable接口
2.再写Tank.java类
3.模拟JDK中的InvocationHandler接口
4.写相应的时间日志操作 如TimeHandler
5.最后是代理类Proxy.java
运行结果为:
静态代理与动态代理的比较
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
JDK动态代理也有缺陷
JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
cglib实例
先导入两个包cglib.jar和asm.jar
Cglib中的被代理类必须实现方法
先写一个HelloImpl.java类
接着LogCglib.java类
测试LogTest2.java
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
代理分为两种:静态代理和动态代理。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在。
动态代理:在程序运行时,利用java的反射机制动态创建而成。
动态代理原理
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接口的子类实例 */
利用JDK的动态代理写一个小Demo.
先一个Hello.java接口
public interface Hello{ void sayHello(String to); void print(String p); }
再写这个接口的实现HelloImpl.java
public class HelloImpl implements Hello { @Override public void sayHello(String to) { System.out.println("Say Hello to " + to); } @Override public void print(String p) { System.out.println("Print: " + p); } }接下来写JDK动态代理代理类LogHandler.java
public class LogHandler implements InvocationHandler { private Object target; public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBefore(); Object result = method.invoke(target,args); doAfter(); return result; } public void doBefore(){ System.out.println("before...."); } public void doAfter(){ System.out.println("after...."); } }
最后写一个测试类LogTest.java
public class LogTest { public static void main(String[] args){ HelloImpl helloImpl = new HelloImpl(); LogHandler logHandler = new LogHandler(helloImpl); Hello hello = (Hello) Proxy.newProxyInstance(helloImpl.getClass().getClassLoader(), helloImpl.getClass().getInterfaces(), logHandler); hello.sayHello("Peter"); hello.print("z"); } }
输出的结果为:
before.... Say Hello tozhangbojun after.... before.... Print: z after....这里我们使用的是JDK中的动态代理来实现。
其实我们可以自己来模拟一个动态代理类来实现相应的功能。
问题描述:为Tank类的move()函数做一个时间日志管理。
1.先写一个Moveable接口
public interface Moveable { void move(); }
2.再写Tank.java类
public class Tank implements Moveable{ @Override public void move() { System.out.println("Tank is moving"); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } }
3.模拟JDK中的InvocationHandler接口
public interface InvocationHandler { public void invoke(Object o,Method method); }
4.写相应的时间日志操作 如TimeHandler
public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { this.target = target; } @Override public void invoke(Object o, Method method) { long start = System.currentTimeMillis(); System.out.println("starttime: " + start); System.out.println(o.getClass().getName()); try { method.invoke(target); } catch (IllegalAccessException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (InvocationTargetException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } long end = System.currentTimeMillis(); System.out.println("time:" + (end - start)); } }
5.最后是代理类Proxy.java
public class Proxy { public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{ //JDK6, Complier API, CGLIB ,ASM String methodStr = ""; String rt = "\r\n"; Method[] methods = infce.getMethods(); for(Method m:methods){ methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt + "}"; } String src = "package org.whut.proxy.proxy;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy1 implements " + infce.getName() + "{" + rt + " public $Proxy1(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " org.whut.proxy.proxy.InvocationHandler h;" + rt + methodStr + "}"; String fileName = "d:/src/org/whut/proxy/proxy/$Proxy1.java";//这里要写在d盘中写见src/org/whut/proxy/proxy文件。要将以上的字符串src写到相应的文件中 File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close(); //编译 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null); Iterable units = fileMgr.getJavaFileObjects(fileName); JavaCompiler.CompilationTask task = compiler.getTask(null,fileMgr,null,null,null,units); task.call(); fileMgr.close(); //加载到内存和生成新对象 URL[] urls = new URL[]{new URL("file:/" + "d:/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("org.whut.proxy.proxy.$Proxy1"); System.out.println(c); Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); return m; } }6.测试其正确性
public class Client { public static void main(String[] args) throws Exception { Tank t = new Tank(); InvocationHandler h = new TimeHandler(t); Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class,h); m.move(); } }
运行结果为:
class org.whut.proxy.proxy.$Proxy1 starttime: 1413718875079 org.whut.proxy.proxy.$Proxy1 Tank is moving time:835
静态代理与动态代理的比较
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
JDK动态代理也有缺陷
JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
cglib实例
先导入两个包cglib.jar和asm.jar
Cglib中的被代理类必须实现方法
先写一个HelloImpl.java类
public class HelloImpl2 { public void sayHello(String to) { System.out.println("Say Hello to " + to); } public void print(String p) { System.out.println("Print: " + p); } }
接着LogCglib.java类
public class LogCglib implements MethodInterceptor { public Object obj; /* 创建代理对象 */ public Object getInstance(Object target){ System.out.println("========"); this.obj = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.obj.getClass()); //回调方法 enhancer.setCallback(this); enhancer.setClassLoader(target.getClass().getClassLoader()); //创建代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { doBefore(); methodProxy.invokeSuper(o,objects); doAfter(); return null; } public void doBefore(){ System.out.println("before...."); } public void doAfter(){ System.out.println("after...."); } }
测试LogTest2.java
public class LogTest2 { public static void main(String[] args){ LogCglib logCglib = new LogCglib(); HelloImpl2 helloImpl = (HelloImpl2) logCglib.getInstance(new HelloImpl2()); helloImpl.sayHello("peter"); helloImpl.print("z"); } }运行结果
======== before.... Say Hello to peter after.... before.... Print: z after....
相关文章推荐
- [转]转个经典的帖子:说故事学设计模式之-Java动态代理模式
- 设计模式之动态代理
- java设计模式之动态代理
- java动态代理设计模式简单示例
- [ 设计模式 ] 动态代理!
- java 设计模式之四-代理模式 java静态代理和动态代理
- 设计模式:用Java动态代理实现AOP
- 设计模式-动态代理
- Java设计模式-动态代理研究分享
- java设计模式之动态代理
- java设计模式_代理模式_动态代理(带例子)
- 代理模式设计(2)-----动态代理
- -java 动态代理设计模式
- Java设计模式Proxy之动态代理
- 设计模式之观察者与动态代理的结合应用
- 设计模式之动态代理
- 设计模式之 动态代理模式
- java设计模式--代理及其动态代理--05
- 用java调用编译器编译java文件-马士兵设计模式教程-动态代理 .
- 使用自动生成java文件和自动编译的动态代理模式-马士兵设计模式教程