AOP编程学习笔记之----JDK动态代理技术

4 篇文章 0 订阅

一、概述

     AOP编程,简称面向切面的编程,是spring框架的一个重要特征,也是日常编程中常用的编程方式,本次冲着对spring打破砂锅问到底的心里,决心弄懂工作中经常出现的一些编程方式和知识点,以前都是在这字面上大大擦边球,希望通过这次学习的机会,把相应的笔记写下来,能够更深一层的了解这些原理,背后的逻辑。在这里介绍AOP的相关概念之前,我们先介绍一种AOP中非常重要的技术:JDK的动态代理技术,AOP编程原理也是使用动态代理技术来实现的,因此我们先了解一下JDK的动态代理技术的原理。


二、JDK动态代理技术

     首先看一下基本概念,当然这些概念笔者也是参考网上的大牛的写文章,代理是一种常用的设计模式,目的就是为其他对象提供一个代理以控制某个对象的访问,消息的处理等。JDK中也提供了相应代理技术,位于java.lang.reflect包下面,这里能了解动态代理技术之前,需要先了解java的反射技术。


2.1 java的反射技术

     java的类是通过被虚拟机加载到内存这当中,才能运行,一般是通过类加载器来加载,而类加载器通常分为3种。一般的流程如下,java源程序文件.java经过java编译器编译之后被转换成java的字节码文件.class文件,通过类加载器加载到内存当中,并实例化成对象,然后才能使用。java的类加载器分为3类:bootstrap class loader (启动类加载器),extensions class loader (扩展类加载器),system class loader (系统类加载器)当然你也可以通过继承ClassLoader类的方式来实现自己的类加载器,同时具体的方式请大家参考网上的博文,说的非常详细。一般java虚拟机启动的时候就会加载很多的字节码文件,这个时候可以直接使用这些类,是因为都事先被类加载器加载到内存当中,然而很多的类并不需要事先被加载,而只需要程序运行的时候才加载,这个时候就需要用到java的反射技术。java的反射技术的特点就是在编译期并没有这个类,并不知道这个类是啥类,直到运行的时候才清楚。举个例子来说,两个程序员同时写代码,A在写程序需要用到B所写的类,此时B并没有完成编写,那么A的代码是不能通过编译的,而通过反射机制,就可以很好的解决这个问题。

   在java的反射API中有几个非常重要的类:

    Class: java中所有的类型都对应一个Class对象,不论一个类产生了多少个对象,但是他们的Class始终只有一个,该Class中包含了该类的所有信息(属性、方法、包等)

     该对象不能通过new的方式来获得,但是可以通过以下三种方式来获得

        1. new 一个对象之后,然后通过getClass()方法 

      	Person p = new Person();
	Class clazz = p.getClass();
       2. 通过Class.forName()的方式获得
         Class.forName("com.org.Person");
        3. 直接通过类的.class
	Class clazz = Person.class;
    Class对象包含了这个类的所有信息,包括构造函数,方法等,具体的使用方法,接下来往下看。

        Field: 代表类中的属性,可以获得其属性,并且修改相应的值,通过Class提供的方法,可以获得方法的所有参数,返回值、作用域、属性等

Field[] fields = clazz.getFields();
        for(Field field:fields){
            System.out.println(field.getName()+"-"+field.getType());
        }
        以上的方法只能获取到共有权限的属性,如果想要获取私有的属性的话,还需要打开对应的权限检查开关
Field[] fds=clazz.getDeclaredFields(); //这个方式可以获取到private属性
        for(Field f:fds){
            System.out.println(f.getName()+"-"+f.getType());
            f.setAccessible(true); //..打开开关之后才能进行相应的设置值

        }

    Method: 代表类中方法,通过反射类可以获取这个类的所有方法,同时,调用Method的invoke()方法可以执行该方法,这也是动态代理经常调用的方法,同样也可以获得方法的所有属性

Class<?>  clazz= Class.forName("com.jdk.proxy.ConstructorDemo"); 
Method[]  methods  = clazz.getMethods();
methods[0].invoke();

   Constructor:类的构造函数,java的反射包中提供了多种方法来回去构造函数,通过构造函数可以直接构造该,通过newInstance()方法来构造实例,这里可以传一些参数类型

Class<?>  clazz= Class.forName("com.jdk.proxy.ConstructorDemo");
        //获取默认的构造函数
Constructor const1 =  clazz.getConstructor(new Class[]{});
const1.newInstance();

    基本上如果使用反射来获取一个类以及其属性,均要用到上面几个一些概念和方法。相对于直接使用一个类,反射使用起来会比较复杂,但是具有非常大的灵活性,被很多的框架中使用。以上就是java反射的一些基本的知识。本文主要讲解的是Spring AOP的概念,而Spring AOP中首先要用到的就是JDK的动态代理技术,而动态代理技术中,需要用到java反射机制,这里先补充一下基本知识。

2.2 JDK的动态代理技术

     介绍完了java的反射技术之后,下面就可以去学习JDK的动态代理技术了,在这里我们首先看一个例子。

 1. 首先定义一个接口FomService和接口的实现类FormServcieImpl(因为jdk的动态代理技术必须要实现接口,后面会说这个问题),这个接口提供了两个方法,根据topic和formId分别进行删除操作,具体的代码如下:

public interface FormService {
    public abstract void remove(int topic);
    public abstract void removeForm(int formid);
}
下面看它的实现类
public class FormServiceImpl implements FormService{
    @Override
    public void remove(int topic) {
        System.out.println("remove form  by topic:"+topic);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void removeForm(int formid) {
        System.out.println("remove form by from Id "+formid);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这里,如果我们要去调用这个方法,同时输出结果,我们看下具体的操作:

 FormService formService = new FormServiceImpl();
 formService.remove(1);
 formService.remove(100);

而输出的结果为:

remove form  by topic:1
remove form  by topic:100

这个结果符合我们的期望,一般也是如此使用,如果现在有个要求,在执行remove的方法之前,需要增加两项功能,1. 打印日志,2.做权限验证,此时方法就变成如下:

public class FormServiceImpl implements FormService{
    @Override
    public void remove(int topic) {
        System.out.println(" 增加权限认证....");
        System.out.println("remove form  by topic:"+topic);
        System.out.println("打印日志....");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void removeForm(int formid) {
        System.out.println(" 增加权限认证....");
        System.out.println("remove form by from Id "+formid);
        System.out.println("打印日志....");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

此时如果采用new的方式来实例化对象,那么所有的方法中都必须增加这么两项1.权限校验,2.打印日志,随着业务越来越膨胀,方法越来越多,添加的逻辑越来越多,整个方法变的越来臃肿,代码越来越复杂,其实验证权限和打印日志属于公共模块,采用一个类来解决即可?那么问题来了,这么去在调用方法前后去调用这两个公用模块呢?,此时就要用到java的动态代理技术。

先来看个例子

FormService obj = new FormServiceImpl();
PerformanceHandler handler = new PerformanceHandler(obj);
FormService proxy = (FormService) Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
proxy.remove(1);
System.out.println("---------method--------------");
proxy.removeForm(100);

查看输出的结果:

 增加权限认证....
remove form  by topic:1
打印日志....
---------method--------------
 增加权限认证....
remove form by from Id 100
打印日志....

很奇怪,原来的方法里面什么都没有加,但是此时两个方法中都在执行之前先进行了权限认证,和之后进行了日志打印操作,这其中到底发生了什么呢?

其实就是把采用了jdk的动态代理技术,把公共模块抽取了出来,下面先看增加的一个类PerformanceHandler,具体代码如下:

public class PerformanceHandler implements InvocationHandler{

    Object obj;
    public PerformanceHandler(Object obj){
        this.obj=obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(" 增加权限认证....");
        Object o = method.invoke(obj,args);
        System.out.println("打印日志....");
        return o;
    }
}

这个类也是非常的简单,只有一个方法invoke,可以看到这个方法中添加了两个功能,就是权限认证和日志打印,这其中到底发生了什么呢?能提供一个这样一个方法,然后改成上面的那种写法,就让两个方法都实现了同样的功能....

下面我们来分析一下,首先看到本次操作增加了PerformanceHandler类,并且实现了一个接口Invocationhandler接口,这个接口查看jdk的源码发现只有一个方法:

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

其中第一个参数代表代理对象,二哥参数代是调用的方法,第三个参数是调用的参数的方法参数,这就可以看出来,在调用这个方法之前,加上需要处理的逻辑,比如权限认证,或者日志打印,都会被执行,因此不管哪儿个方法来调用这个方法,都会被执行的。那么这个invoke方法啥时候被调用呢?源码中的注释说明,在代理对象上调用方法时候,关联在这个代理对象的上的invokeHandler对象会调用自己的invoke方法,这个在后面的源码中也能看到。

接下来,我们看下对FormService这个类如何实例化的,可以看到上面的方法中有个非常重要的类Proxy,这是jdk反射包中提供个代理类,提供了一个静态的newProxyInstance(...)方法如下:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)throws IllegalArgumentException

这个方法需要传入3个参数,第一个参数是Classloader ,这个是定义这个代理类的Classloader,一般传入的classloader 是创建接口的class loader,保证生产的代理类能够转换成接口被我们使用,第二个是interface,需要代理类实现的接口,这就是为啥一定要先写个接口了,因为这个方法需要传入接口作为参数,第三个参数是InvocationHandler,这就是后来增加的实现类,具体实现看下文。这里通过代理类,返回了一个实体类,然后执行这个实体类,即可触发对应的方法,同时织入我们的handler方法编写的逻辑。

小结: 这里通过java的反射机制,利用代理的方式,得到了一个FormService的代理类,在执行对应的remove方法的时候会自动触发handler的invoke方法,那么此时,卸载该方法的中的一些逻辑就会被执行,包括权限认证和日志打印,因此整个程序中只需在handler中写一个这样的逻辑,所有的方法都可以调用他,这就是AOP的概念了。

--------分割线--------------

Java的动态代理技术使用起来很简单,就是简单的Proxy类InvocationHandler接口,然后实例化一个代理类即可,那么究竟Proxy.newInstance()方法是如何获取一个代理类,同时调用对应的方法的呢?下面我们来阅读以下 jdk的这部分源码,感兴趣的同学可以继续往下阅读,不感兴趣的,可以忽略这部分内容....

首先看下Proxy.newInstance()方法

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)throws IllegalArgumentException
    {
        Objects.requireNonNull(h);   //判断是否为空

        final Class<?>[] intfs = interfaces.clone();    //拷贝参数传进来的接口
        final SecurityManager sm = System.getSecurityManager();  //一些安全权限检查
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //或者构造函数
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});  //返回实例化对象
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

上面这个方法还是比较简单的,其中主要的流程如下

1. 生成代理类的Proxy的Class对象,这是整个方法中最核心的地方

Class<?> cl = getProxyClass0(loader, intfs);

2. 获取相应的构造函数,如果该函数的作用域为私有域,则通过setAccessible方法来支持访问

 final Constructor<?> cons = cl.getConstructor(constructorParams);
     final InvocationHandler ih = h;
     if (!Modifier.isPublic(cl.getModifiers())) {
     AccessController.doPrivileged(new PrivilegedAction<Void>() {
         public Void run() {
             cons.setAccessible(true);
             return null;
          }
     });
}
这里就是前面用到的反射技术,通过获取到的Class对象,来得到对应的构造方法,和作用域等。

3. 获取Proxy Class的构造函数,创建Proxy的代理实例,整个过程就此结束

cons.newInstance(new Object[]{h});
以上三步中,可以看出最核心的地方就是生成Class对象,这里我们看一下该方法:
private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        return proxyClassCache.get(loader, interfaces);
    }
这个方法相对比较简单,就是做了一个判断,接口的数量不能超过65535,然后调用了proxyClassCache.get方法,这个proxyClassCached这里主要用作缓存的,下面看下他的get方法
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
        
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

下面我们来详解说明一下这个方法

首先,这个方法咋一看,挺负责的,很多变量,一看就花眼了,那么我们反过来看,看这个方法的返回值,return value,这个value也是个泛型,通过如下方法得到:

V value = supplier.get();

而这个supplier的类型是一个接口,并且只有一个方法get:

public interface Supplier<T> {
    T get();
}

而得到这个supplier则是通过一个map来获取的,而此时用到一个key subKey,接下来看看这个subKey是啥时候put进去呢?

Supplier<V> supplier = valuesMap.get(subKey);
这就清晰了,要想获得supplier,就需要从根据subKey从valueMap中获取对应的值:
 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

其实这个supplier也是一个factory,实现了supplier接口,内部报错了下面重点分析一下subKeyFactory.apply(key,paramter)这个方法,其实这个subKeyFactory也是个工厂类,这里我们看下apply方法

    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
               
                throw new IllegalArgumentException(e.toString());
            }
        }
可以看到这个方法接收了两个参数,一个是classloader,第二个是接口,首先便利了所有接口,同时通过Class.forName(),去得到这些接口的Class对象,接着验证Class对象是不是接口,如下代码:
 if (!interfaceClass.isInterface()) {
      throw new IllegalArgumentException(
         interfaceClass.getName() + " is not an interface");
}
如果不是,则抛出异常,接着验证接口是否重复,
 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
      throw new IllegalArgumentException(
            "repeated interface: " + interfaceClass.getName());
  }

接下来验证你的接口中是否有非public的接口,只要有一个接口是非public,那么些这些接口都必须在同一个包中,如果验证通过,所有接口都是public,那么生成的代理类的包名为默认的com.sun.proxy,接下面做一些基本的处理,比如生成的类名,第一个生成的类名$Proxy0.class,在接下来,得到一个非常重要的方法ProxyGenerator.generateProxyCLass(...)来生成字节码文件。

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

在接下来,返回生成的对象,下面我们来看下这个生成字节码的方法,该方法返回了一个byte[]字节数组,那么这个数组里面到底是啥,待会在细节看一下

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();  //这里是动态生成字代理类的字节码
        if(saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if(var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
                            Files.createDirectories(var3, new FileAttribute[0]);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class", new String[0]);
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

可以看到上面的参数,saveGeneratedFiles=true,来把字节码写入到磁盘当中,生成.calss文件,那么这个属性是如何得到的呢,

    private static final boolean saveGeneratedFiles = ((Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();

这个getBooleanAction实际上是调用Boolean.getBoolean(this.theProp) 方法来获得的,实际上,我们可以通过设置com.misc.ProxyGnerator.saveGeneratedFiles这个系统属性为true来进行保存,当然不止这一种方法了,也可以通过获取得到byte[]数组,然后通过文件的fileoutStream来写入到磁盘中。

Boolean.valueOf(Boolean.getBoolean(this.theProp)
接下来,通过下面一段代码,把获得到的代理类写入到磁盘上:

     byte[] clazzByte= ProxyGenerator.generateProxyClass("FormService",new Class[]{FormService.class});
        try {
            FileOutputStream out = new FileOutputStream(new File("/tmp/FormService.class"));
            out.write(clazzByte);
            out.flush();;
            System.out.println("finished@");
        } catch (Exception e) {
            e.printStackTrace();
        }
下面通过反编译工具JD-GUI来反编译一下源码,
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class FormService
  extends Proxy
  implements com.jdk.proxy.FormService
{
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;
  private static Method m4;
  
  public FormService(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void remove(int paramInt)
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void removeForm(int paramInt)
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("com.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m4 = Class.forName("com.jdk.proxy.FormService").getMethod("removeForm", new Class[] { Integer.TYPE });
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

这个类中有几个要注意的地方,首先生成的这个类名是实现了FormService接口,同时继承了Proxy这个类

public final class FormService extends Proxy implements com.jdk.proxy.FormService
同时它有5个变量
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
private static Method m4;
try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m4 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("removeForm", new Class[] { Integer.TYPE });
      return;
    }

可以看到这个5方法中,有3个方式Object的方法,这里重新实现了equals,toString和hashCode这个几个方法,还有两个方法分别是接口中的方法remove和removeForm这两个方法。接下来看下这两个方法

 public final void remove(int paramInt)
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
这里代理类实现了接口中的方法,可以看到出来调用这个方法的时候,有是h.invoke()方法执行的,那么这个h是啥呢?
 public FormService(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
看下该类的构造函数,给了一个参数Invocationhandler,然调用了父类的构造函数
protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }
那么很明显这个this.h其实就是我们自定义的InvocationHandler,在回过头来看下Performancehandler这个类,其中只有个invoke方法,那么调用这个方法我们看下参数
this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
 m3 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(" 增加权限认证....");
        Object o = method.invoke(obj,args);
        System.out.println("打印日志....");
        return o;

    }
这很清楚了,先调用了权限认证,然后在调用了method.invode(),最后调用了打印日志这个方法,最后返回结果,整个流程到这里就结束了,这下就很清楚了,这个invoke方法的执行流程。

三、总结
    到这里,整个jdk的动态代理的源码解析到此结束,这里做一个小结
   1. 代理类基础了Proxy,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类,不能在继承其他类,所以jdk的动态代理不支持对已实现类的代理,只能支持接口的代理
   2. 将自己实现的InvocationHandler作为构造函数的参数传入了进来,用来调用invoke方法

   3. 生成静态方法Method,已经重新覆盖了toString,hashcode和equals方法

  jdk动态代理是AOP编程的基础,同时也是各大框架中使用非常频繁的技术,本次在学习的过程中做一个小结,下一篇,将详细介绍一下spring AOP的编程实现原理...





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值