动态代理的使用以及其实现机制
2013-05-21 15:38
483 查看
一、动态代理的使用
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
动态代理主要包含以下角色:
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。
代理接口 是代理类实现的一个接口。
代理实例 是代理类的一个实例。
每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
下面看一个例子:
1.代理接口:IComputer.java
2.被代理对象:Laptop.java
3.调用处理类:TimeHander.java
4.测试程序:
程序运行结果:
start:1369118281186
电脑正在执行中......
end:1369118282849
total:1663
二、动态代理运行机制
Proxy.
为了能够更加的理解动态代理的运行机制,我自己来实现了一个动态代理:
1.代理接口:Moveable.java
2.被代理对象:Tank.java
3.下面写一个Proxy类来为被代理对象产生一个代理类对象,来实现增加记录运行时间的功能。
4.TankProxy.java
5.测试程序:
执行该程序的结果为:
start:1369121253400
Tank moving...
end:1369121260078
time:6678
动态生成的代理类的内容如下:
看了这个例子,对动态代理的实现机制应该会有一定的了解了!
小结:动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
动态代理主要包含以下角色:
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。
代理接口 是代理类实现的一个接口。
代理实例 是代理类的一个实例。
每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口
InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 )]
Invoke方法,并传递代理实例、识别调用方法的
java.lang.reflect.Method对象以及包含参数的
Object类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现
下面看一个例子:
1.代理接口:IComputer.java
package com.proxy; public interface IComputer { void execute(); }
2.被代理对象:Laptop.java
package com.proxy; //笔记本电脑 public class Laptop implements IComputer { public void execute() { System.out.println("电脑正在执行中......"); } }
3.调用处理类:TimeHander.java
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeHander implements InvocationHandler { private Object object; public TimeHander(Object object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); System.out.println("start:"+start); method.invoke(object, args); Thread.sleep((int)(Math.random()*2000)); long end = System.currentTimeMillis(); System.out.println("end:"+end); System.out.println("total:"+(end-start)); return null; } }
4.测试程序:
package com.proxy; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { Laptop laptop = new Laptop(); TimeHander hander = new TimeHander(laptop); IComputer computer = (IComputer)Proxy.newProxyInstance(laptop.getClass().getClassLoader(), laptop.getClass().getInterfaces(), hander); computer.execute(); } }
程序运行结果:
start:1369118281186
电脑正在执行中......
end:1369118282849
total:1663
二、动态代理运行机制
Proxy.
, java.lang.reflect.InvocationHandler)]newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法会返回一个代理对象类的实例。如上面例子中IComputer computer = (IComputer)Proxy.newProxyInstance(laptop.getClass().getClassLoader(), laptop.getClass().getInterfaces(), hander);执行这一句话的时候会通过反射机制动态的生成一个代理类,该类实现了IComputer接口,并且重写了接口里面的方法(也就是说代理类与被代理类有相同的接口),在该代理类里面有一个InvocationHandler类型的成员变量,也就是调用处理程序,通过调用处理程序来给被代理类增强功能。创建好代理类后就调用类加载器将该类加载到类存,然后再通过反射创建一个该代理类的实例对象。
为了能够更加的理解动态代理的运行机制,我自己来实现了一个动态代理:
1.代理接口:Moveable.java
package com.test; public interface Moveable { void move(); }
2.被代理对象:Tank.java
package com.test; import java.util.Random; public class Tank implements Moveable { public void move() { System.out.println("Tank moving..."); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
3.下面写一个Proxy类来为被代理对象产生一个代理类对象,来实现增加记录运行时间的功能。
package com.test; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class Proxy { public static Object newProxyInstance(Class interfaces,InvocationHandler h)throws Exception{ StringBuffer methodStr = new StringBuffer(); String tr = "\r\n"; Method[] methods = interfaces.getMethods(); //拼接代理类的方法 for (Method method : methods) { methodStr.append( " public "+ method.getReturnType()+ " " +method.getName()+"() {" + tr + " try {" + tr + " java.lang.reflect.Method md = " + interfaces.getName() + "." + "class.getMethod(\"" + method.getName() + "\");" + tr + " h.invoke(this,md);" + tr + " }catch(Exception e) {e.printStackTrace();}" + tr + " }" + tr ); } //拼接代理类 String src = "package com.test;" + tr + "import com.test.Moveable;" + tr + "public class TimeProxy implements " + interfaces.getName() + " {" + tr + " private com.test.InvocationHandler h;" + tr + " public TimeProxy(com.test.InvocationHandler h) {" + tr + " this.h = h;" + tr + " }" + tr + methodStr.toString() + tr + "}"; //创建代理类 String fileName = System.getProperty("user.dir") + "/src/com/test/TimeProxy.java"; File file = new File(fileName); FileWriter writer = new FileWriter(file); writer.write(src); writer.flush(); writer.close(); //编译 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(fileName); CompilationTask ct = compiler.getTask(null, fileMgr, null, null, null, units); ct.call(); fileMgr.close(); //加载类到内存: Class c = ClassLoader.getSystemClassLoader().loadClass("com.test.TimeProxy"); Constructor constructor = c.getConstructor(InvocationHandler.class); //得到参数为InvocationHandler类型的构造方法 Object m = constructor.newInstance(h); //通过该构造方法得到实例 return m; } }
4.TankProxy.java
package com.test; import java.lang.reflect.Method; public class TankProxy { public static <T> T getBean(final Object tank) throws Exception{ return (T)Proxy.newProxyInstance(tank.getClass().getInterfaces()[0], new InvocationHandler(){ public void invoke(Object proxy, Method method) { long start = System.currentTimeMillis(); System.out.println("start:"+start); try { method.invoke(tank, new Object[]{}); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("end:"+end); System.out.println("time:"+(end-start)); } }); } }
5.测试程序:
package com.test; import java.util.List; import com.extend.Tank2; import com.extend.Tank3; import com.juhe.LogProxy; import com.juhe.TimeProxy; public class Test { public static void main(String[] args) throws Exception { Tank tank = new Tank(); Moveable m = TankProxy.getBean(tank); m.move(); } }
执行该程序的结果为:
start:1369121253400
Tank moving...
end:1369121260078
time:6678
动态生成的代理类的内容如下:
package com.test; import com.test.Moveable; public class TimeProxy implements com.test.Moveable { private com.test.InvocationHandler h; public TimeProxy(com.test.InvocationHandler h) { this.h = h; } public void move() { try { java.lang.reflect.Method md = com.test.Moveable.class.getMethod("move"); h.invoke(this,md); }catch(Exception e) {e.printStackTrace();} } }
看了这个例子,对动态代理的实现机制应该会有一定的了解了!
小结:动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。
相关文章推荐
- 动态代理的使用以及其实现机制
- JAVAWEB开发之Servlet3.0新特性的使用以及注解的详细使用和自定义注解的方法、动态代理的使用、利用动态代理实现细粒度的权限控制以及类加载和泛型反射
- 详解java动态代理机制以及使用场景(一)
- 使用DBUtils、动态代理以及注解实现事务控制
- PHP实现依赖注入-使用反射机制和动态代理技术 - 简单思想(咋个办呢 zgbn)
- PHP中使用反射机制实现动态代理
- 动态代理的使用和实现机制
- 动态代理使用以及Proxy的内部实现
- Java反射机制使用场景,以及基于javaReflect Java动态代理实现
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
- Spring事务管理机制的实现原理-动态代理
- 什么时候使用事件代理,事件委托机制实现
- Spring_AOP_XML使用Aspect实现动态代理(常用) .
- JDK使用InvocationHandler和Proxy实现动态代理
- Java的动态代理机制和Spring的实现方式
- Spring AOP的实现机制(一)----- 动态代理
- Mybatis总结2使用动态代理 实现接口
- java 使用动态代理 和ThreadLocal实现事务管理实例
- Aop之使用Castle动态代理实现对方法的拦截
- 使用 JAVA 中的动态代理实现数据库连接池