黑马程序员 Java自学总结二十 Java高新技术第三天

------ ASP.Net+Android+IO开发.Net培训期待与您交流! ------

总结内容来源于张孝祥老师的Java高新技术

代理

代理的概念与作用

为其他对象提供一种代理以控制对这个对象的访问 . 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.

代理模式简单示例

[java]  view plain copy
  1. //目标类:       
  2.  class A       
  3.  {      
  4.    void sayHello()      
  5.    {      
  6.      System.out.println("hello itcast");      
  7.    }      
  8.  }      
  9.        
  10. // 代理类:      
  11. AProxy      
  12.  {      
  13.    void sayHello()      
  14.    {      
  15.      starttime;      
  16.      A.sayHello();      
  17.      endTime;      
  18.    }       
  19.  }     

程序中的代理
1.要为已存在的多个具有相同接口的目标类的各个方法增加一系列的系统功能,例如,异常处理,日志、计算方法等的运行时间、事务管理等等,你如何做?
2.编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
3.如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类,这样以后很容易切换。譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易。以后运行一段时间后,又想去掉系统功能也很容易。

代理分为两种:静态代理和动态代理。  
 <AOP>
1.系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方法。
2.交叉业务的房产问题即为面向方面的编程(AOP,Aspect oriented program),AOP的目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编程切面代码的运行效果是一样的。
3.使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。


动态代理技术(JVM动态代理和CGLIB库动态代理)
1.要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。(引出动态代理)
2.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作 代理类 ,即动态代理类。
3.JVM生成的动态类必须具有一个或多个接口,所以,JVM生成的动态类(Proxy)只能用作具有相同接口的目标类的代理。
4.CGLIB库(一个开源库)可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的 类生成动态代理类,可以使用CGLIB库。

代理类的各个方法中通除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下 四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法之前或之后
4.在处理目标方法异常的catch块中。

创JVM动态代理的三种方法:

[java]  view plain copy
  1. package study.day3;  
  2. import java.lang.reflect.Constructor;  
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6. import java.lang.reflect.Proxy;  
  7. import java.util.ArrayList;  
  8. import java.util.Collection;  
  9.   
  10. public class ProxytTest {  
  11.     public static void main(String[] args) throws Exception {  
  12.         Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);  
  13.         System.out.println(clazzProxy.getName());  
  14.           
  15.                 //获取代理类的所有构造方法  
  16.         Constructor[] constructors = clazzProxy.getConstructors();  
  17.         System.out.println("--------------------constructors--------------------");  
  18.         for(Constructor constructor : constructors){  
  19.             String constructorName = constructor.getName();  
  20.             System.out.print(constructorName);  
  21.             StringBuilder sb = new StringBuilder();  
  22.             sb.append("(");  
  23.             Class[] clazzParams = constructor.getParameterTypes();  
  24.             for(Class clazzParam : clazzParams){  
  25.                 sb.append(clazzParam.getName()+",");  
  26.             }  
  27.             if(clazzParams != null && clazzParams.length != 0)  
  28.                 sb.deleteCharAt(sb.length()-1);  
  29.             sb.append(")");  
  30.             System.out.println(sb.toString());            
  31.         }  
  32.             //获取代理类的所有方法  
  33.         Method[] methods = clazzProxy.getMethods();  
  34.         System.out.println("--------------------methods--------------------");  
  35.         for(Method method : methods){  
  36.             String constructorName = method.getName();  
  37.             System.out.print(constructorName);  
  38.             StringBuilder sb = new StringBuilder();  
  39.             sb.append("(");  
  40.             Class[] clazzParams = method.getParameterTypes();  
  41.             for(Class clazzParam : clazzParams){  
  42.                 sb.append(clazzParam.getName()+",");  
  43.             }  
  44.             if(clazzParams != null && clazzParams.length != 0)  
  45.                 sb.deleteCharAt(sb.length()-1);  
  46.             sb.append(")");  
  47.             System.out.println(sb.toString());            
  48.         }    
  49.   
  50.         //获取代理类的实例对象                  
  51.         System.out.println("--------------------instance--------------------");               
  52.         Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);      
  53.   
  54.         //获取代理类对象的方法一 : 用代理类的构造方法类和实现了接口的类  
  55.         class MyInvocationHandler implements InvocationHandler{  
  56.             @Override  
  57.             public Object invoke(Object proxy, Method method, Object[] args)  
  58.                     throws Throwable {  
  59.                 // TODO Auto-generated method stub  
  60.                 return null;  
  61.             }             
  62.         }         
  63.         Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler());       
  64.         //获取代理类对象的方法二 : 用代理类的构造方法类和匿名内部类  
  65.         Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){  
  66.             @Override  
  67.             public Object invoke(Object proxy, Method method, Object[] args)  
  68.                     throws Throwable {  
  69.                 return null;  
  70.             }});  
  71.          //获取代理类对象的方法三 : 用Proxy的newProxyInstance方法  
  72.          Collection proxy3 = (Collection)Proxy.newProxyInstance(  
  73.              Collection.class.getClassLoader(),  
  74.              new Class[]{Cellection.class},   
  75.              new InvocationHandler(){  
  76.                  ArrayList target = new ArrayList();  
  77.                  @Override  
  78.                  public Object invoke(Object proxy, Method method, Object[] args)  
  79.                          throws Throwable {  
  80.                       long before = System.currentTimeMillis();  
  81.                       Object reValue = method.invoke(target, args);  
  82.                       long after = System.currentTimeMillis();                          
  83.                       System.out.println(method.getName()+"---runtime---"+(after-before));  
  84.                       return reValue;  
  85.                   }  
  86.               }  
  87.           );  
  88.       }  
  89. }  


注意 : Object 继承来的方法  只有 toString , hashCode , equals ,   调用时委托给 InvocationHandler, 其他的方法 Proxy 自己都有实现 .


使动态生成的类成为任意目标的代理

动态代理类的骨架使用Proxy.newProxyInstance()方法生成,执行时再传入两个参数:要代理的目标target和增加的系统功能的封装对象(advice),再把它们封装成一个方法.


[java]  view plain copy
  1. //advise实现的接口  
  2. package study.day3;  
  3. import java.lang.reflect.Method;  
  4.   
  5. public interface Advise {  
  6.     void before(Method method);  
  7.     void after(Method method);  
  8. }  
  9. //advise  
  10. package study.day3;  
  11.   
  12. import java.lang.reflect.Method;  
  13.   
  14. public class MyAdvise implements Advise {  
  15.     long before = 0;  
  16.     public void before(Method method) {  
  17.         System.out.println("努力进黑马");  
  18.         before = System.currentTimeMillis();  
  19.     }  
  20.     public void after(Method method) {  
  21.         System.out.println("学习学习再学习");  
  22.         long after = System.currentTimeMillis();                          
  23.         System.out.println(method.getName()+"---runtime---"+(after-before));  
  24.     }  
  25. }  
  26. package study.day3;  
  27. import java.lang.reflect.InvocationHandler;  
  28. import java.lang.reflect.InvocationTargetException;  
  29. import java.lang.reflect.Proxy;  
  30. import java.util.ArrayList;  
  31. import java.util.Collection;  
  32. public class ProxytTest {  
  33.     public static void main(String[] args) throws Exception {  
  34.         ArrayList target = new ArrayList();  
  35.         Advise advise = new MyAdvise();  
  36.         //调用方法  
  37.         Collection proxy4 = (Collection) getProxy(target,advise);  
  38.         //封装的方法  
  39.         private static Object getProxy(final Object target,final Advise advise) {  
  40.         Object proxy4 = Proxy.newProxyInstance(  
  41.                 target.getClass().getClassLoader(),  
  42.                 target.getClass().getInterfaces(),   
  43.                 new InvocationHandler(){  
  44.                     @Override  
  45.                     public Object invoke(Object proxy, Method method, Object[] args)  
  46.                             throws Throwable {  
  47.                         /*long before = System.currentTimeMillis(); 
  48.                         Object reValue = method.invoke(target, args); 
  49.                         long after = System.currentTimeMillis();                         
  50.                         System.out.println(method.getName()+"---runtime---"+(after-before)); 
  51.                         return reValue;*/  
  52.                           
  53.                         advise.before(method);  
  54.                         Object reValue = method.invoke(target, args);  
  55.                         advise.after(method);  
  56.                         return reValue;  
  57.                     }  
  58.                 }  
  59.                 );  
  60.         return proxy3;  
  61.     }  
  62. }  

实现可配置的AOP(面向方面)框架

需求:Bean工厂BeanFactory负责创建配置文件中读取出的目标类的Bean , 如果读取到的是BeanFactoryProxy则调用BeanFactoryProxy的getProxy方法 , 返回目标类的代理

代码:

[java]  view plain copy
  1. package com.study.day3.aopframework;  
  2. import java.io.InputStream;  
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5.   
  6. public class AopFranmeworkTest {  
  7.   
  8.     public static void main(String[] args) throws Exception {  
  9.           
  10.         InputStream is = AopFranmeworkTest.class.getResourceAsStream("config.properties");  
  11.         Collection bean = (Collection) new BeanFactory(is).getBean("xxx");  
  12.         System.out.println(bean.getClass().getName());  
  13.         System.out.println(bean.getClass().getMethod("add", Object.class)  
  14.                 .getName());  
  15.         bean.add("123");  
  16.         System.out.println(bean.size());  
  17.     }  
  18. }  
  19. package com.study.day3.aopframework;  
  20.   
  21. import java.io.IOException;  
  22. import java.io.InputStream;  
  23. import java.util.Properties;  
  24. import com.study.day3.Advise;  
  25. //BeanFactory类,用于返回Bean,如果配置文件中是读取的是BeanFactoryProxy,则调用BeanFactoryProxy返回代理  
  26. public class BeanFactory {  
  27.     Properties props = new Properties();  
  28.     BeanFactory(InputStream is) throws Exception{  
  29.         props.load(is);  
  30.     }  
  31.     public Object getBean(String name) throws Exception{  
  32.         String className = props.getProperty(name);  
  33.         Class clazz = Class.forName(className);  
  34.         Object bean = clazz.newInstance();  
  35.         if(bean instanceof BeanFactoryProxy){  
  36.             BeanFactoryProxy beanFactoryProxy = (BeanFactoryProxy)bean;  
  37.             Advise advise = (Advise)Class.forName(props.getProperty(name+".advise")).newInstance();  
  38.             Object target = Class.forName(props.getProperty(name+".target")).newInstance();  
  39.             //System.out.println(target.getClass().getName());  
  40.             beanFactoryProxy.setAdvise(advise);  
  41.             beanFactoryProxy.setTarget(target);  
  42.             return beanFactoryProxy.getProxy();  
  43.         }  
  44.         return bean;  
  45.     }  
  46. }  
  47. package com.study.day3.aopframework;  
  48.   
  49. import java.lang.reflect.InvocationHandler;  
  50.   
  51. import java.lang.reflect.Method;  
  52. import java.lang.reflect.Proxy;  
  53. import com.study.day3.Advise;  
  54. import com.study.day3.MyAdvise;  
  55. //BeanFactoryProxy类,用于返回代理  
  56. public class BeanFactoryProxy {  
  57.     private Advise advise = null;  
  58.     private Object target = null;     
  59.     public void setAdvise(Advise advise) {  
  60.         this.advise = advise;  
  61.     }  
  62.     public void setTarget(Object target) {  
  63.         this.target = target;  
  64.     }  
  65.   
  66.     public Object getProxy() {  
  67.         Object proxy = Proxy.newProxyInstance(  
  68.                 target.getClass().getClassLoader(),  
  69.                 target.getClass().getInterfaces(),  
  70.                 new InvocationHandler() {             
  71.             @Override  
  72.             public Object invoke(Object proxy, Method method, Object[] args)  
  73.                     throws Throwable {  
  74.                 Advise advise = new MyAdvise();  
  75.                 advise.before(method);  
  76.                 Object reValue = method.invoke(target, args);  
  77.                 advise.after(method);  
  78.                 return reValue;  
  79.             }  
  80.         });  
  81.         return proxy;  
  82.     }  
  83. }  
  84. package com.study.day3;  
  85.   
  86. import java.lang.reflect.Method;  
  87.   
  88. public interface Advise {  
  89.     void before(Method method);  
  90.     void after(Method method);  
  91. }  
  92. package com.study.day3;  
  93.   
  94. import java.lang.reflect.Method;  
  95.   
  96. public class MyAdvise implements Advise {  
  97.     long before = 0;  
  98.     public void before(Method method) {  
  99.         System.out.println("努力进黑马");  
  100.         before = System.currentTimeMillis();  
  101.     }  
  102.   
  103.     public void after(Method method) {  
  104.         System.out.println("学习学习再学习");  
  105.         long after = System.currentTimeMillis();                          
  106.         System.out.println(method.getName()+"---runtime---"+(after-before));  
  107.     }  
  108.   
  109. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值