的应用以及其实现机制

    添加时间:2013-5-21 点击量:

      一、的应用


      可以供给对另一个对象的接见,同时隐蔽实际对象的具体事实。一般会实现它所默示的实际对象的接口。可以接见实际对象,然则延迟实现实际对象的项目组功能,实际对象实现体系的实际功能,对象对客户隐蔽了实际对象。客户不知道它是与打交道还是与实际对象打交道。


      首要包含以下角色:


      类(以下简称为)是一个实如今创建类时在运行时指定的接口列表的类,该类具有下面描述的行动。


      接口 是类实现的一个接口。


      实例 是类的一个实例。


      每个实例都有一个接洽关系的调用处理惩罚法度 对象,它可以实现接口 InvocationHandler。经由过程此中一个接口的实例上的办法调用将被指派到实例的调用处理惩罚法度的 Invoke 办法,并传递实例、辨认调用办法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理惩罚法度以恰当的体式格式处理惩罚编码的办法调用,并且它返回的成果将作为实例上办法调用的成果返回。


      


      今朝Java开辟包中包含了对的支撑,然则其实现只支撑对接口的的实现。 其实现首要经由过程java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 Proxy类首要用来获取对象,InvocationHandler接口用来束缚调用者实现


      下面看一个例子:


      1.接口:IComputer.java



    1 package com.proxy;
    
    2
    3 public interface IComputer {
    4 void execute();
    5 }


      2.被对象:Laptop.java



     1 package com.proxy;
    
    2
    3 //笔记本电脑
    4 public class Laptop implements IComputer {
    5
    6 public void execute() {
    7 System.out.println(电脑正在履行中......);
    8 }
    9
    10 }


      3.调用处理惩罚类:TimeHander.java



     1 package com.proxy;
    
    2
    3 import java.lang.reflect.InvocationHandler;
    4 import java.lang.reflect.Method;
    5
    6 public class TimeHander implements InvocationHandler {
    7 private Object object;
    8 public TimeHander(Object object) {
    9 this.object = object;
    10 }
    11 public Object invoke(Object proxy, Method method, Object[] args)
    12 throws Throwable {
    13 long start = System.currentTimeMillis();
    14 System.out.println(start:+start);
    15 method.invoke(object, args);
    16 Thread.sleep((int)(Math.random()2000));
    17 long end = System.currentTimeMillis();
    18 System.out.println(end:+end);
    19 System.out.println(total:+(end-start));
    20 return null;
    21 }
    22
    23 }


      4.测试法度:



     1 package com.proxy;
    
    2
    3 import java.lang.reflect.Proxy;
    4
    5 public class ProxyTest {
    6
    7 public static void main(String[] args) {
    8 Laptop laptop = new Laptop();
    9 TimeHander hander = new TimeHander(laptop);
    10 IComputer computer = (IComputer)Proxy.newProxyInstance(laptop.getClass().getClassLoader(), laptop.getClass().getInterfaces(), hander);
    11 computer.execute();
    12 }
    13
    14 }



    法度运行成果:


    start:1369118281186
    电脑正在履行中......
    end:1369118282849
    total:1663



      二、运行机制


      Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 办返回一个对象类的实例。如上方例子中IComputer computer = (IComputer)Proxy.newProxyInstance(laptop.getClass().getClassLoader(), laptop.getClass().getInterfaces(), hander);履行这一句话的时辰会经由过程反射机制动态的生成一个类,该类实现了IComputer接口,并且重写了接口里面的办法(也就是说类与被类有雷同的接口),在该类里面有一个InvocationHandler类型的成员变量,也就是调用处理惩罚法度,经由过程调用处理惩罚法度来给被类加强功能。创建好类后就调用类加载器将该类加载到类存,然后再经由过程反射创建一个该类的实例对象。


      为了可以或许加倍的懂得的运行机制,我本身来实现了一个:


      1.接口:Moveable.java



    1 package com.test;
    
    2
    3 public interface Moveable {
    4 void move();
    5 }


      2.被对象:Tank.java



     1 package com.test;
    
    2
    3 import java.util.Random;
    4
    5 public class Tank implements Moveable {
    6
    7 public void move() {
    8 System.out.println(Tank moving...);
    9 try {
    10 Thread.sleep(new Random().nextInt(10000));
    11 } catch (InterruptedException e) {
    12 e.printStackTrace();
    13 }
    14 }
    15
    16 }


      3.下面写一个Proxy类来为被对象产生一个类对象,来实现增长记录运行时候的功能。



     1 package com.test;
    
    2
    3 import java.io.File;
    4 import java.io.FileWriter;
    5 import java.lang.reflect.Constructor;
    6 import java.lang.reflect.Method;
    7
    8 import javax.tools.JavaCompiler;
    9 import javax.tools.StandardJavaFileManager;
    10 import javax.tools.ToolProvider;
    11 import javax.tools.JavaCompiler.CompilationTask;
    12
    13 public class Proxy {
    14 public static Object newProxyInstance(Class interfaces,InvocationHandler h)throws Exception{
    15 StringBuffer methodStr = new StringBuffer();
    16 String tr = \r\n;
    17 Method[] methods = interfaces.getMethods();
    18 //拼接类的办法
    19 for (Method method : methods) {
    20 methodStr.append(
    21 public + method.getReturnType()+ +method.getName()+() { + tr +
    22 try { + tr +
    23 java.lang.reflect.Method md = + interfaces.getName() + . + class.getMethod(\ + method.getName() + \); + tr +
    24 h.invoke(this,md); + tr +
    25 }catch(Exception e) {e.printStackTrace();} + tr +
    26 } + tr
    27 );
    28 }
    29
    30 //拼接类
    31 String src = package com.test; + tr +
    32 import com.test.Moveable; + tr +
    33 public class TimeProxy implements + interfaces.getName() + { + tr +
    34 private com.test.InvocationHandler h; + tr +
    35 public TimeProxy(com.test.InvocationHandler h) { + tr +
    36 this.h = h; + tr +
    37 } + tr +
    38 methodStr.toString() + tr +
    39 };
    40 //创建类
    41 String fileName = System.getProperty(user.dir) + /src/com/test/TimeProxy.java;
    42 File file = new File(fileName);
    43 FileWriter writer = new FileWriter(file);
    44 writer.write(src);
    45 writer.flush();
    46 writer.close();
    47 //编译
    48 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    49 StandardJavaFileManager fileMgr = compiler.getStandardFileManager(nullnullnull);
    50 Iterable units = fileMgr.getJavaFileObjects(fileName);
    51 CompilationTask ct = compiler.getTask(null, fileMgr, nullnullnull, units);
    52 ct.call();
    53 fileMgr.close();
    54 //加载类到内存:
    55 Class c = ClassLoader.getSystemClassLoader().loadClass(com.test.TimeProxy);
    56 Constructor constructor = c.getConstructor(InvocationHandler.class); //获得参数为InvocationHandler类型的机关办法
    57 Object m = constructor.newInstance(h); //经由过程该机关办法获得实例
    58 return m;
    59
    60 }
    61 }


      4.TankProxy.java



     1 package com.test;
    
    2
    3 import java.lang.reflect.Method;
    4
    5 public class TankProxy {
    6 public static <T> T getBean(final Object tank) throws Exception{
    7 return (T)Proxy.newProxyInstance(tank.getClass().getInterfaces()[0], new InvocationHandler(){
    8 public void invoke(Object proxy, Method method) {
    9 long start = System.currentTimeMillis();
    10 System.out.println(start:+start);
    11 try {
    12 method.invoke(tank, new Object[]{});
    13 } catch (Exception e) {
    14 e.printStackTrace();
    15 }
    16 long end = System.currentTimeMillis();
    17 System.out.println(end:+end);
    18 System.out.println(time:+(end-start));
    19 }
    20
    21 });
    22 }
    23 }


      5.测试法度:



     1 package com.test;
    
    2
    3 import java.util.List;
    4
    5 import com.extend.Tank2;
    6 import com.extend.Tank3;
    7 import com.juhe.LogProxy;
    8 import com.juhe.TimeProxy;
    9
    10 public class Test {
    11 public static void main(String[] args) throws Exception {
    12 Tank tank = new Tank();
    13 Moveable m = TankProxy.getBean(tank);
    14 m.move();
    15
    16 }
    17
    18 }


    履行该法度的成果为:
    start:1369121253400
    Tank moving...
    end:1369121260078
    time:6678


    动态生成的类的内容如下:



     1 package com.test;
    
    2 import com.test.Moveable;
    3 public class TimeProxy implements com.test.Moveable {
    4 private com.test.InvocationHandler h;
    5 public TimeProxy(com.test.InvocationHandler h) {
    6 this.h = h;
    7 }
    8 public void move() {
    9 try {
    10 java.lang.reflect.Method md = com.test.Moveable.class.getMethod(move);
    11 h.invoke(this,md);
    12 }catch(Exception e) {e.printStackTrace();}
    13 }
    14
    15 }


      


      看了这个例子,对的实现机制应当会有必然的懂得了!


       小结:在运行期经由过程接口动态生成类,这为其带来了必然的灵活性,但这个灵活性却带来了两个题目,第一类必须实现一个接口,若是没实现接口会抛出一个异常。第二机能影响,因为应用反射的机制实现的,起首反射必然比直接调用要慢,其次应用反射多量生成类文件可能引起Full GC造成机能影响,因为字节码文件加载后会存放在JVM运行时区的办法区(或者叫持久代)中,当办法区满的时辰,会引起Full GC,所以当你多量应用时,可以将持久代设置大一些,削减Full GC次数。 


     

    彼此相爱,却不要让爱成了束缚:不如让它成为涌动的大海,两岸乃是你们的灵魂。互斟满杯,却不要同饮一杯。相赠面包,却不要共食一个。一起歌舞欢喜,却依然各自独立,相互交心,却不是让对方收藏。因为唯有生命之手,方能收容你们的心。站在一起却不要过于靠近。—— 纪伯伦《先知》
    分享到: