zoukankan      html  css  js  c++  java
  • java Proxy(代理机制)

      我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。

      在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:

    InvocationHandler:

    InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
    
    Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    
    proxy:  指代我们所代理的那个真实对象
    method:  指代的是我们所要调用真实对象的某个方法的Method对象
    args:  指代的是调用真实对象某个方法时接受的参数

    如果不是很明白,等下通过一个实例会对这几个参数进行更深的讲解。

    接下来我们来看看Proxy这个类:

    Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 

    Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
    Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

    这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:

    复制代码
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    
    loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    
    interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    
    h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
    复制代码

    好了,下面给出代理样例:

    首先我们定义了一个HjzggMethod类型的接口

    package com.hjzgg.proxy;
    
    public interface HjzggMethod {
        public int addMethod(int a, int b);
        public int subMethod(int a, int b);
    }

    接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,HjzggMethodImpl 类

    package com.hjzgg.proxy;
    
    public class HjzggMethodImpl implements HjzggMethod {
    
        @Override
        public int addMethod(int a, int b) {
            System.out.println("我执行了!");
            return a+b;
        }
    
        @Override
        public int subMethod(int a, int b) {
            return a-b;
        }
    
    }

    创建动态代理类,这个类并没有实现InvocationHandler ,而是在类方法中间接的创建一个InvocationHandler 实例

    package com.hjzgg.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    
    public class MethodProxy {
        private HjzggMethod target;
        public MethodProxy(HjzggMethod target)
        {
            super();
            this.target = target;
        }
        public HjzggMethod getMethodProxy()
        {
            HjzggMethod proxy = null;
            //代理对象由哪一个类加载器加载
            ClassLoader loader = target.getClass().getClassLoader();
            //代理对象的类型,即其中有哪些方法
            //Class[] interfaces = new Class[]{HjzggMethod.class};
            Class[] interfaces = target.getClass().getInterfaces();
            //当调用代理对象其中的方法时,该执行的代码
            InvocationHandler h = new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
                    String methodName = method.getName();
                    System.out.println(method);
                    System.out.println("the method: " + methodName + "开始, 参数: "+Arrays.asList(args));
                    Object result = method.invoke(target, args);
                    System.out.println("the method: "+methodName+"结束, 结果: " + result);
                    return result;
                }
            };
            proxy=(HjzggMethod) Proxy.newProxyInstance(loader, interfaces, h);
            return proxy;
        }
    }

    最后测试类如下:

    package com.hjzgg.proxy;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    
    public class ProxyTest {
        
        public static String getModifier(int modifier){
          String result = "";
          switch(modifier){
               case Modifier.PRIVATE:
                result = "private";
               case Modifier.PUBLIC:
                result = "public";
               case Modifier.PROTECTED:
                result = "protected";
               case Modifier.ABSTRACT :
                result = "abstract";
               case Modifier.FINAL :
                result = "final";
               case Modifier.NATIVE :
                result = "native";
               case Modifier.STATIC :
                result = "static";
               case Modifier.SYNCHRONIZED :
                result = "synchronized";
               case Modifier.STRICT  :
                result = "strict";
               case Modifier.TRANSIENT :
                result = "transient";
               case Modifier.VOLATILE :
                result = "volatile";
               case Modifier.INTERFACE :
                result = "interface";
              }
              return result;
         }
             
         public static void printClassDefinition(Class clz){
              String clzModifier = getModifier(clz.getModifiers());
              if(clzModifier!=null && !clzModifier.equals("")){
                  clzModifier = clzModifier + " ";
              }
              String superClz = clz.getSuperclass().getName();
              if(superClz!=null && !superClz.equals("")){
                  superClz = "extends " + superClz;
              }
              
              Class[] interfaces = clz.getInterfaces();
              String inters = "";
              for(int i=0; i<interfaces.length; i++){
                   if(i==0){
                       inters += "implements ";
                   }
                   inters += interfaces[i].getName();
              }
              System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
              System.out.println("{");
              
              Field[] fields = clz.getDeclaredFields();
              for(int i=0; i<fields.length; i++){
                   String modifier = getModifier(fields[i].getModifiers());
                   if(modifier!=null && !modifier.equals("")){
                       modifier = modifier + " ";
                   }
                   String fieldName = fields[i].getName();
                   String fieldType = fields[i].getType().getName();
                   System.out.println("    "+modifier + fieldType + " "+ fieldName + ";");
              }
              
              System.out.println();
              
              Method[] methods = clz.getDeclaredMethods();
              for(int i=0; i<methods.length; i++){
                   Method method = methods[i];
                   String modifier = getModifier(method.getModifiers());
                   if(modifier!=null && !modifier.equals("")){
                       modifier = modifier + " ";
                   }
               
                   String methodName = method.getName();
                   
                   Class returnClz = method.getReturnType();
                   String retrunType = returnClz.getName();
                   
                   Class[] clzs = method.getParameterTypes();
                   String paraList = "(";
                   for(int j=0; j<clzs.length; j++){
                        paraList += clzs[j].getName();
                        if(j != clzs.length -1 ){
                            paraList += ", ";
                        }
                   }
                   paraList += ")";
               
                   clzs = method.getExceptionTypes();
                   String exceptions = "";
                   for(int j=0; j<clzs.length; j++){
                        if(j==0){
                            exceptions += "throws ";
                        }
            
                        exceptions += clzs[j].getName();
                    
                        if(j != clzs.length -1 ){
                         exceptions += ", ";
                        }
                   }
                   exceptions += ";";
                   String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
                   System.out.println("    "+methodPrototype );
              }
              System.out.println("}");
         }
        
        public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
            HjzggMethod method = new HjzggMethodImpl();
            System.out.println(method.getClass().getMethod("addMethod", int.class, int.class));
            HjzggMethod methodProxy = new MethodProxy(method).getMethodProxy();
            methodProxy.addMethod(10, 20);
            
            printClassDefinition(methodProxy.getClass());
        }
    }

    最后的输出结果:

    public int com.hjzgg.proxy.HjzggMethodImpl.addMethod(int,int)
    public abstract int com.hjzgg.proxy.HjzggMethod.addMethod(int,int)
    the method: addMethod开始, 参数: [10, 20]
    the method: addMethod结束, 结果: 30
    $Proxy0 extends java.lang.reflect.Proxy implements com.hjzgg.proxy.HjzggMethod
    {
        java.lang.reflect.Method m1;
        java.lang.reflect.Method m3;
        java.lang.reflect.Method m0;
        java.lang.reflect.Method m4;
        java.lang.reflect.Method m2;
    
        int subMethod(int, int);
        boolean equals(java.lang.Object);
        java.lang.String toString();
        int hashCode();
        int addMethod(int, int);
    }

      从输出结果来看,原来通过 HjzggMethod methodProxy = new MethodProxy(method).getMethodProxy();得到的HjzggMethod 实例其实是继承自Proxy 的,并且实现了HjzggMethod (我们之前定义的接口)接口中的方法。在实现的方法(比如addMethod)中是通过 InvocationHandler 调用invoke方法,然后InvocationHandler的invoke方法中又调用method中的invoke来实现。执行的顺序是  methodProxy.addMethod(10, 20); -> InvocationHandler中的invoke() -> method中的invoke()。还有就是method这个对象是可以通过接口.class来获得的。method.invoke(obj, args)中的obj实体一定是实现了该method对应的接口。恰巧我们在创建代理对象的时候,(HjzggMethod) Proxy.newProxyInstance(loader, interfaces, h),也有interfaces(接口的字节码文件对象)。

    通过下面的例子,你就可以轻松的理解InvocationHandler中invoke()方法中的method是如何得来的!

    Method method = HjzggMethod.class.getMethod("addMethod", int.class, int.class);//通过HjzggMethod接口得到Methed实例

    HjzggMethod hjzggMethod
    = new HjzggMethodImpl();//创建实现HjzggMethod接口的HjzggMethodImpl对象
    method.invoke(hjzggMethod, 10, 20);//执行方法, 相当于hjzggMethod.addMethod(10, 20);
  • 相关阅读:
    从零开始——PowerShell应用入门(全例子入门讲解)
    详解C# Tuple VS ValueTuple(元组类 VS 值元组)
    How To Configure VMware fencing using fence_vmware_soap in RHEL High Availability Add On——RHEL Pacemaker中配置STONITH
    DB太大?一键帮你收缩所有DB文件大小(Shrink Files for All Databases in SQL Server)
    SQL Server on Red Hat Enterprise Linux——RHEL上的SQL Server(全截图)
    SQL Server on Ubuntu——Ubuntu上的SQL Server(全截图)
    微软SQL Server认证最新信息(17年5月22日更新),感兴趣的进来看看哟
    Configure Always On Availability Group for SQL Server on RHEL——Red Hat Enterprise Linux上配置SQL Server Always On Availability Group
    3分钟带你了解PowerShell发展历程——PowerShell各版本资料整理
    由Find All References引发的思考。,
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/4872856.html
Copyright © 2011-2022 走看看