zoukankan      html  css  js  c++  java
  • java中的静态代理和动态代理

    1、动态代理的定义:为其他对象提供一个代理以控制对这个对象的访问

    代理类主要负责委托类的预处理消息,过滤消息,把消息传给委托类以及消息事后处理

    按照代理类的创建时期,代理类可以分为2种:静态代理类(在程序运行前代理类.class文件就以及生成)和动态代理类(字节码是在程序运行时由java反射机制动态生成)

    静态代理的实例:

    package com.vcredit.ddcash.decision;

    public class ProxyTest {
    public static void main(String[] args) {
    HelloService helloService = new HelloServiceImpl();
    HelloServiceProxy helloServiceProxy = new HelloServiceProxy(helloService);
    helloServiceProxy.say();
    }

    }

    interface HelloService{
    void say();

    }
    class HelloServiceImpl implements HelloService{
    public void say(){
    System.out.println(11);
    };

    }
    class HelloServiceProxy implements HelloService{
    public HelloService helloService;
    HelloServiceProxy(HelloService helloService){
    this.helloService=helloService;
    }
    public void say(){
    System.out.println("预处理");
    helloService.say();//调用被代理的HellService的say方法
    System.out.println("事后处理");
    };
    }

    2、通过api看下proxy生成代理类的2中写法:

    创建某一接口 Foo 的代理:

         InvocationHandler handler = new MyInvocationHandler(...);
         Class proxyClass = Proxy.getProxyClass(
             Foo.class.getClassLoader(), new Class[] { Foo.class });
         Foo f = (Foo) proxyClass.
             getConstructor(new Class[] { InvocationHandler.class }).
             newInstance(new Object[] { handler });
     

    或使用以下更简单的方法:

         Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                              new Class[] { Foo.class },
                                              handler);
    其实第二中写法就相当于对第一中写法的封装,具体看Proxy这个类;

    3、具体实例:

    public interface Subject  
    {  
      public void doSomething();  
    }  
    public class RealSubject implements Subject  
    {  
      public void doSomething()  
      {  
        System.out.println( "call doSomething()" );  
      }  
    }  
    public class ProxyHandler implements InvocationHandler  
    {  
      private Object proxied;  
        
      public ProxyHandler( Object proxied )  
      {  
        this.proxied = proxied;  
      }  
        
      public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable  
      {  
        //在转调具体目标对象之前,可以执行一些功能处理

        //转调具体目标对象的方法
        return method.invoke( proxied, args); 
       
        //在转调具体目标对象之后,可以执行一些功能处理
      }   
    }

    import java.lang.reflect.InvocationHandler;  
    import java.lang.reflect.Method;  
    import java.lang.reflect.Proxy;  
    import sun.misc.ProxyGenerator;  
    import java.io.*;  
    public class DynamicProxy  
    {  
      public static void main( String args[] )  
      {  
        RealSubject real = new RealSubject();  
        Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
         new Class[]{Subject.class},
         new ProxyHandler(real));//要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
            
        proxySubject.doSomething();
      
        //write proxySubject class binary data to file  
        createProxyClassFile();  
      }  
        
      public static void createProxyClassFile()  
      {  
        String name = "ProxySubject";  
        byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );  
        try 
        {  
          FileOutputStream out = new FileOutputStream( name + ".class" );  
          out.write( data );  
          out.close();  
        }  
        catch( Exception e )  
        {  
          e.printStackTrace();  
        }  
      }  
    }

    分析:当调用proxySubject.doSomething();时,就调用了$proxy0类中的doSomething()方法,在doSomething()方法中调用父类

    proxy中h的invoke()方法,即InvercationHandler.invoke(),这个流程可以通过代理类的.class文件反编译后查看

    部分截图:

    public final void doSomething() {
       try {
        super.h.invoke(this, m3, null);
        return;
       } catch (Error e) {
       } catch (Throwable throwable) {
        throw new UndeclaredThrowableException(throwable);
       }
    }

    下面看下通过Proxy类的静态方法getProxyClass生成的class文件经过反编译后生成的代码:

    public final class $Proxy0
    extends Proxy
    implements Subject{
    ---表名是一个最终类,此类继承了Proxy类,实现了Subject接口

    public $Proxy0(InvocationHandler invocationHandler) {
            super(invocationHandler);
        }

    里面有一个带参数的构造方法,通过getProxyClass(...).getConstructor(parameterType p)//这个参数应该就是InvocationHandler这个接口类,从而通过super调用父类的带参构造器,从而给就有了InvocationHandler这个接口

     protected Proxy(InvocationHandler h) {
     this.h = h;
        }

    当调用$Proxy0类的doSomething()方法时:会调用h.invoke(...)方法

    public final String doSomething() {
            try {
                return (String)this.h.invoke((Object)this, m3, new Object[]{});
            }
            catch (Error | RuntimeException v0) {
                throw v0;
            }
            catch (Throwable var2_2) {
                throw new UndeclaredThrowableException(var2_2);
            }
        }
    看下invoke方法的3个参数 第一个指的就是被代理的类的实例也就是对应的RealSubject实例

    m3指的是对应的方法

    m3 = Class.forName("****.Subject").getMethod("doSomething");
    第三个参数指的就是方法中的参数,没有参数就是null

    再通过反射机制就可以唯一确定调用被代理类中的相关方法

    4、Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。

    Cglib动态代理 
    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    还是举例说明:

    public class BookImpl{//没有实现接口
     public void add(){
      System.out.println("这是一个新增的方法");
     }

    }

    import java.lang.reflect.Method;

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;

    //创建代理类,这个类实现MethodInterceptor接口
    public class BookProxy  implements MethodInterceptor {

     private Object target;
     
     public BookProxy(Object target){
      this.target=target;
     }
     
     @Override
     public Object intercept(Object arg0, Method arg1, Object[] arg2,
       MethodProxy arg3) throws Throwable {
      System.out.println("事务开始");
      Object result = arg3.invokeSuper(target, arg2);
      System.out.println("事务结束");
      return result;
     }

    }

    //测试类


    public class TestCglib {
     public static void main(String[] args){
      
     BookImpl bi = new BookImpl();

     BookProxy bp = new BookProxy(bi);
     BookImpl bii = (BookImpl)Enhancer.create(bi,bp);
      bii.add();
     }

    }

    //输出结果

    事务开始
    这是一个新增的方法
    事务结束

  • 相关阅读:
    Golang项目之函数版学生管理系统
    Golang项目之结构体版学生管理系统
    Golang基础之结构体
    前端开发必备组件库【基于原生js、兼容主流浏览器、B/S必备】
    兼容主流浏览器的js原生函数封装
    基于原生js的返回顶部组件,兼容主流浏览器
    javascript数组详解(js数组深度解析)【forEach(),every(),map(),filter(),reduce()】
    javascript中的字符串编码、字符串方法详解
    面试题中常见的类型转换陷阱
    node.js报错throw err; // Rethrow non-MySQL errors e:serverTest ode_modulesmysqllibprotocolParser.js:79 解决方法
  • 原文地址:https://www.cnblogs.com/muliu/p/5498390.html
Copyright © 2011-2022 走看看