zoukankan      html  css  js  c++  java
  • 反射 动态代理

     之前参与一个项目,使用的技术框架是struts2+ibatis,业余好奇探索了下,于是有幸接触到Java的反射和动态代理。我知道在struts2的拦截器中使用了反射和动态代理,

    据说很多经典的框架,比如springhibernate、ibatis等也都大范围使用了。这两种技术大概意思如下:

    反射:在程序运行的时候,动态的获取某个类中的属性和方法,并且能够调用(很多框架能自动识别你写的类,然后调用一些共同的方法,靠的就是它)。

    代理:给类包装上一层壳,通过这个壳去操作这个类,使得你在操作这个类之前之后可以做一些你想做的事情。

    反射介绍

    反射比较简单,主要使用Class类,Class类提供了运行时获取或调用某个类具体内容的方法。如下代码作实例:

    待调用的类MyClass:

     
    1. public class MyClass {  
    2.     private int myInt;  
    3.     private String myString;  
    4.   
    5.     public MyClass(){  
    6.   
    7.     }  
    8.   
    9.     public MyClass(int a){  
    10.         this.myInt = a;  
    11.     }  
    12.   
    13.     public void Method2Void(){  
    14.   
    15.     }  
    16.   
    17.     public int Method2Int(){  
    18.         System.out.println("Method2Int has run");  
    19.         return 0;  
    20.     }  
    21.   
    22.     public String Method2String(){  
    23.         return "";  
    24.     }  
    25.   
    26.     public Object Method2Object() {  
    27.         return new Date();  
    28.     }  
    29.   
    30.     public void Method3Param(int a, String b){  
    31.         System.out.println("Method3Param has run with param-a:" + a + " and param-b:" + b);  
    32.     }  
    33. }  


    Main函数

     
    1. public static void main(String[] args){  
    2.     MyClass myClass = new MyClass();  
    3.     Class cls = myClass.getClass();//获取一个类的Class  
    4.   
    5.     System.out.println("1:" + cls.getName());//名字  
    6.     System.out.println("2:" + cls.getSimpleName());  
    7.     System.out.println("3:" + cls.getPackage());  
    8.     try{  
    9.         Method m = cls.getMethod("Method2Int", new Class[]{});//获取一个类的方法  
    10.         m.invoke(myClass, new Object[]{});//精髓所在,调用这个类的方法  
    11.   
    12.         Method m2 = cls.getMethod("Method3Param", new Class[]{int.class, String.class});  
    13.         m2.invoke(myClass, new Object[]{5, "fake"});//调用这个类的方法,带参数的  
    14.     }catch(Exception e){  
    15.         e.printStackTrace();  
    16.     }  
    17.     Method[] ms = cls.getMethods();  
    18.   
    19.     for(Method m:ms){  
    20.         System.out.println(m.getName());  
    21.     }  
    22.   
    23.   
    24.     try{  
    25.         Class cls2 = Class.forName("MyClass");//这种方法也能获取一个类的Class,同时能动态载入这个类  
    26.     }catch(Exception e){  
    27.         e.printStackTrace();  
    28.     }  
    29. }  

    下面详细介绍下代理

          代理这种现象在生活中是非常常见的,比如你要买火车票,可以让你的朋友帮你买,也可以托代售点帮你买。你把钱给了他们,他们可能会做任何事情。也许你朋友忘记;或者代售点把你黑了。当然,程序是你的,你可以控制他们的行为。

          代理有普通代理和动态代理。上面说的你的朋友,可以看成是普通代理,代售点可以看成是动态代理。区别在于,你的朋友并不会帮每个人都买票,仅仅帮他认识少部分人买,而代售点是来者不拒的,具有通用性。

          使用代理模式,需要区分真实对象和代理对象。代理对象中含有真实对象的引用,可以对真实对象进行操作,调用真实对象的方法。可以通过调用代理对象的方法,间接的去调用真实对象的方法。

    下面还是举例来说说这两种代理吧。

    以下是这两种代理所需的类:

    行为PersonAct.java


     
    1. package proxy;  
    2.   
    3. public interface PersonAct {  
    4.     void buyTicket();//买票  
    5.     void checkProperty();//查看财产  
    6. }  

    抽象类Person.java


     
    1. import java.util.Map.Entry;  
    2.   
    3. public abstract class Person implements PersonAct{  
    4.     //全部家当放在这个HashMap里  
    5.     HashMap<String, Object> property = new HashMap<String, Object>();  
    6.       
    7.     String name;  
    8.       
    9.     public Person(String name, int money){  
    10.         this.name= name;  
    11.         this.property.put("money", money);  
    12.     }  
    13.       
    14.     //打印目前家当  
    15.     public void checkProperty(){  
    16.         System.out.println(this.name + "的家当如下:");  
    17.         Iterator<Entry<String, Object>> iter = property.entrySet().iterator();  
    18.         while(iter.hasNext()){  
    19.             Entry<String, Object> entry = (Entry<String, Object>)iter.next();  
    20.             System.out.println(entry.getKey() + "---" + entry.getValue());  
    21.         }          
    22.     }             
    23. }  

    真实类Boy.java

     
    1. package proxy;  
    2.   
    3. public class Boy extends Person{  
    4.       
    5.     public Boy(String name, int money){  
    6.         super(name, money);  
    7.     }  
    8.       
    9.     //买票  
    10.     @Override  
    11.     public void buyTicket() {  
    12.         int money = (Integer)property.get("money");  
    13.           
    14.         property.put("money", money - 38);//扣钱  
    15.         property.put("ticket", "北京到上海机票");//拿票          
    16.     }  
    17. }  

    真实类Girl.java

     
    1. package proxy;  
    2.   
    3. public class Girl extends Person{  
    4.       
    5.     public Girl(String name, int money){  
    6.         super(name, money);  
    7.     }      
    8.       
    9.     @Override  
    10.     public void buyTicket() {  
    11.         int money = (Integer)property.get("money");  
    12.           
    13.         property.put("money", money - 46);//扣钱  
    14.         property.put("ticket", "北京到深圳机票");//拿票      
    15.     }          
    16. }  

    上面的类Boy和Girl代表现实生活中的两个人,Boy自己去买票的过程如下。

     
    1. Boy boy = new Boy("西门庆", 100);          
    2. boy.checkProperty();  
    3. boy.buyTicket();  
    4. boy.checkProperty();  

    结果将会打印出boy购票前和投票后的家当。

    1,普通代理

    类FatherOfBoy.java

     
    1. package proxy;  
    2.   
    3. public class FatherOfBoy {  
    4.     private Boy boy = new Boy("西门庆", 100);  
    5.       
    6.     public void buyTicket(){  
    7.         boy.buyTicket();  
    8.     }  
    9.       
    10.     public void checkProperty(){  
    11.         boy.checkProperty();  
    12.     }  
    13. }  

    概念很好理解,普通代理买票可以这样测试

     
    1. FatherOfBoy father = new FatherOfBoy();  
    2. father.checkProperty();  
    3. father.buyTicket();  
    4. father.checkProperty();  

    2,  动态代理

    动态代理主要通过继承InvocationHandler接口来实现。

    ProxyAgency.java如下:

     
    1. package proxy;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Method;  
    5.   
    6. public class ProxyAgency implements InvocationHandler{  
    7.     private Person target;//真实对象的引用  
    8.       
    9.     public void setTarget(Person target) {  
    10.         this.target = target;  
    11.     }  
    12.   
    13.     public ProxyAgency(){  
    14.           
    15.     }  
    16.       
    17.     public ProxyAgency(Person obj){  
    18.         this.setTarget(obj);  
    19.     }  
    20.       
    21.     //obj,这个是代理对象  
    22.     //method,具体调用的方法  
    23.     //args,调用方法的时候传进来的参数,一般都直接传给真实对象即可  
    24.     @Override  
    25.     public Object invoke(Object obj, Method method, Object[] args) throws Throwable {  
    26.         //target,真实对象,收取手续费10元  
    27.         if(method.getName().equalsIgnoreCase("buyTicket")){  
    28.             int money = Integer.parseInt(target.property.get("money").toString());  
    29.             target.property.put("money", money - 10);  
    30.         }  
    31.         //target,真实对象,下面一句属于java反射机制的东西,用反射机制获取真实对象的方法          
    32.         return method.invoke(target, args);//调用真实对象的方法  
    33.     }  
    34. }  

    调用实例:

     
    1.         //代理对象构建器  
    2.         ProxyAgency proxyAgency = new ProxyAgency();  
    3.           
    4.         //真实对象  
    5.         Boy b = new Boy("西门庆", 100);  
    6.         Girl g = new Girl("潘金莲", 200);          
    7.           
    8.         //代理对象,获取方法1  
    9.         PersonAct p1 = (PersonAct) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{ PersonAct.class }, proxyAgency);  
    10.           
    11.         //真实对象注入构建器,也可以在构建器的构造函数中注入  
    12.         proxyAgency.setTarget(b);          
    13.           
    14.           
    15.         //代理对象获取方法2  
    16. //        Class<?> cls = g.getClass();  
    17. //        PersonAct p1 = (PersonAct) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), proxyAgency);  
    18.           
    19.         p1.checkProperty();  
    20.         p1.buyTicket();  
    21.         p1.checkProperty();  
    22.           
    23.         proxyAgency.setTarget(g);  
    24.           
    25.         p1.checkProperty();  
    26.         p1.buyTicket();  
    27.         p1.checkProperty();  


    输出如下:

    西门庆的家当如下:
    money---100
    西门庆的家当如下:
    ticket---北京到上海机票
    money---52
    潘金莲的家当如下:
    money---200
    潘金莲的家当如下:
    ticket---北京到深圳机票
    money---144

  • 相关阅读:
    团队项目----数据库SQL语句学习总结与实践
    团队项目----德州扑克数据库设计之改进版
    期末项目《员工考勤管理系统》
    Applet
    Json
    study of javaserver faces lifecycle
    Session
    xml的用途,定义,原理,以及前景
    互联网应用于企业级应用的区别
    JavaEE体系架构
  • 原文地址:https://www.cnblogs.com/jtlgb/p/6365993.html
Copyright © 2011-2022 走看看