zoukankan      html  css  js  c++  java
  • 代理

    代理就像个中介,最外层操作代理对象,代理对象再调用委托对象

    当需要在调用前后做一些处理,但是这些处理与业务逻辑无关的时候,如果把无关代码写在业务逻辑里面,代码就会变得很乱,这时候用代理就再好不过了。

    就像spring的aop编程,也是用了代理,在调用前后做一些校验、日志记录等无关业务流程的事

    因为要通过代理对象去调用委托对象,所以代理对象需要持有委托对象的引用,而且代理类中需要实现委托对象的各种方法

    代理有两种一种是静态代理、一种是动态代理

    静态代理是由自己编写代理类,但是代理类都相差无几,而且要每一个类都编写一个代理类的话,就会有太多的类了

    动态代理是由反射技术,自动生成代理类,运行期才生成class文件

    动态代理有两种实现方法,一种是java.lang.reflect、一种是cglib

    jdk自带的实现方法,委托类只能实现接口,不能继承类,所有具有一定的局限性

    cglib,委托类既可以实现接口也可以继承类

    下面通过一个例子来说明代码

    代理 - 钟绍威 - 1

    一个Book接口,接口有read方法,有一个EBook类实现Book接口

    //Book接口
    public interface Book {
     public void read();
    }
     
    //委托类
    class EBook implements Book {
     @Override
     public void read() {
      System.out.println("读电子书");
     }
    }

    静态代理

    代理 - 钟绍威 - 2

    比原本的代码多了一个BookProxy

    //代理类
    public class BookProxy implements Book{
     //持有Book委托实例
     private Book book;
     //绑定Book委托实例并返回代理对象
     public Book bind(Book book){
     this.book=book;
     return this;
     }
     //委托book调用read
     public void read(){
     try{
     //前置代码
     book.read();
     //后置代码
     }catch(Exception e){
     //异常代码
     }finally{
     //finall代码
     }
     }
    }

    可以看到,代理的本质就是,代理类持有委托对象,通过代理对象去调用委托对象,在调用的时候就可以添加一些额外代码

    jdk实现动态代理

    代理 - 钟绍威 - 3

    这里的BookProxy,是使用反射,在运行期自动生成的

    重要的是InvocationHandler,调用反射对象的时候,实际上是调用了InvocationHandler.invoke()

    所以需要实现InvocationHandler接口,让实现类持有委托类引用,并且重写invoke方法

    //代理类
    public class BookInvocationHandler implements InvocationHandler {
     //委托类
     private Object target;
     
     //绑定委托类 并 返回一个代理对象
     public Object bind(Object target){
     this.target=target;
     return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     }
     //调用委托对象
     //proxy是代理对象,method是要调用的方法,arg是方法的参数
     @Override
     public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
     Object result = null;
     try{
     //前置代码
     result=method.invoke(proxy,arg);
     //后置代码
     }catch(Exception e){
     //异常代码
     }finally{
     //finally代码
     }
     return result;
     }
    }

    这里需要注意两个地方

    • Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)通过newProxyInstance拿到代理对象,主要参数,loader:委托类的类加载器,interfaces实现的接口,h调用处理程序
    • InvocationHandler.invoke(Object proxy, Method method, Object[] arg)
      这里的参数proxy是代理对象!所以调用委托对象的时候不能是method.invoke(proxy,arg),不然会循环调用invoke的,要invoke绑定的委托类对象

    jdk不能代理继承的类,要代理继承的类,要用cglib去实现

    cglib实现动态代理

    代理 - 钟绍威 - 4

    这里和jdk实现方法差不多,就是InvocationHandler换成了MethodInterceptor

    proxy还是用反射在运行期生成,只是他用Enhancer.create()

    public class BookInterceptor implements MethodInterceptor {
     
     private Object target;
     public Object bind(Object target) { 
     this.target = target; 
     Enhancer enhancer = new Enhancer(); 
     //设置父类
     enhancer.setSuperclass(this.target.getClass()); 
     // 回调方法 
     enhancer.setCallback(this); 
     // 创建代理对象 
     return enhancer.create(); 
     } 
     
     //obj委托对象 mehtod要拦截的方法 args参数 proxy也是要拦截的方法(更快)
     @Override
     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
     method.invoke(target, args);
     return null;
     }
     
    }
  • 相关阅读:
    Java多线程性能优化
    It is indirectly referenced from required .class files
    Switch基本知识
    HibernateTemplate 查询
    Hibernate工作原理及为什么要用?
    深入Java集合学习系列:HashMap的实现原理
    sql查询语句中的乱码 -- 前面加N
    Windows 8.1内置微软五笔输入法
    the rendering library is more recent than your version of android studio
    JBoss vs. Tomcat
  • 原文地址:https://www.cnblogs.com/wewill/p/5668788.html
Copyright © 2011-2022 走看看