zoukankan      html  css  js  c++  java
  • cglib的最初版本干了什么?

    因为翻阅spring的源码,看到overrides部分,牵扯到了cglib,加上后续马上要进行的aop也要用到这个玩意儿,其实知道一些,说是用继承的方法解决代理的问题。

    跟jdkproxy经常拿来比较,当然这两个也是面试经常问的问题,当然还是那句话,就木有一个技术难点经得起细看, 都是点只是没看到的点而已,然后就会被人鄙视说这都不会,只想说,去你大爷的,老子只是没看。

    好了废话说多无益,来看下最初的版本吧,往往最初的版本是最核心的东西,之后的种种不过是锦上添花,那这锦才是最需要研究的。

    github上cglib的版本最早的是

    2002年的版本,我们把代码下载下来只有三个类。

    把源码拿到后,做了个例子看下,确实比较猛。

    先看下代码:

    /*
     * Factory.java
     *
     */
    
    package proxy.net.sf.cglib.proxy;
    
    /**
     *
     * @author  user
     */
      public interface Factory{
          
           public Object newInstance(MethodInterceptor ih);
        }
       
        
    public interface MethodInterceptor {
        
        /** Generated code calls this method first
         * @param obj this
         * @param method Intercepted method
         * @param args Arg array
         * @throws Throwable  any exeption to stop execution
         * @return returned value used as parameter for all
         * interceptor methods
         */    
      /*  public Object beforeInvoke( Object obj,
                                    java.lang.reflect.Method method,
                                    Object args[] )throws java.lang.Throwable;
       */
        
        /** Generated code calls this method before invoking super
         * @param obj this
         * @param method Method
         * @param args Arg array
         * @param retValFromBefore value returned from beforeInvoke
         * @throws Throwable any exeption to stop execution
         * @return true if need to invoke super
         */    
        public boolean invokeSuper(Object obj,
                                   java.lang.reflect.Method method,
                                   Object args[]
                /*,Object retValFromBefore*/)
                                                 throws Throwable;
        
        /** this method is invoked after execution
         * @param obj this
         * @param method Method
         * @param args Arg array
         * @param retValFromBefore value returned from beforeInvoke
         * @param invokedSuper value returned from invoke super
         * @param retValFromSuper value returner from super
         * @param e Exception thrown by super
         * @throws Throwable any exeption
         * @return value to return from generated method
         */    
        public Object afterReturn(Object obj,
                                  java.lang.reflect.Method method,
                                  Object args[],
                /*Object retValFromBefore,*/
                                  boolean invokedSuper,
                                  Object retValFromSuper,
                                  Throwable e)
                                                 throws Throwable;
        
        
    }

    另一个就是类:Enhance.java ,这个是核心类,内容比较多,这里就不贴出来了。后边我们的分析里,主要就是Enhance里的代码在做代码增强。

    下边我们来看下我们写的测试的例子:

    定义一个接口

    package cglib.test;
    
    public interface Call {
    
        void call();
        void eat();
    }

    定义实例:

    package cglib.test;
    
    public class Dog implements Call{
    
        @Override
        public void call() {
            System.out.println("wang!wang!");
        }
    
        @Override
        public void eat() {
            System.out.println("eat!eat!");
        }
    }

    测试类:

    package cglib.test;
    
    import proxy.net.sf.cglib.proxy.Enhancer;
    import proxy.net.sf.cglib.proxy.MethodInterceptor;
    
    import java.lang.reflect.Method;
    
    public class CglibTest {
    
    
        public static void main(String args[]){
    try {
                Dog dog = (Dog)Enhancer.enhance(Dog.class, null, new MethodInterceptor() {
                    @Override
                    public boolean invokeSuper(Object obj, Method method, Object[] args) throws Throwable {
    
                        if(method.getName().equals("eat")){
                            System.out.println("before eat invoke ...");
                        }else if(method.getName().equals("call")){
                            System.out.println("before call invoke ...");
                        }
                        return true;
                    }
    
                    @Override
                    public Object afterReturn(Object obj, Method method, Object[] args, boolean invokedSuper, Object retValFromSuper, Throwable e) throws Throwable {
                        System.out.println("after invoke ...");
                        return obj;
                    }
                }, CglibTest.class.getClassLoader());
    
                dog.call();
                dog.eat();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
    
        }
    
    }

    测试结果:

    before call invoke ...
    wang!wang!
    after invoke ...
    before eat invoke ...
    eat!eat!
    after invoke ...

    可以看到已经根据我们实现的MethodInteceptor进行了增强,输出我们想要的内容了。

    嗯,代码拿下来后,我是新创建的工程放入代码的,发现有编译错误,查看import的错误,是缺少bcel jar包。去apache官网上下载一个相对比较老的5.2的版本。

    没错就是这个包,查了下,就是用来生成增强类的。只不过后来cglib的这块儿引用被asm替换掉了,当然asm应该是比bcel更强悍的。不过既然要看最初的版本,那我们就还是按照这个版本来看吧。那就避免不了要看bcel的东西了。

    花点时间跟踪下bcel的代码我们来看下最终生成的类:

    生成的类名字:cglib.test.Dog$$EnhancedBySimplestore$$0

    生成的类的call方法:

    重点看下:21步/32步/53步

    其实已经很明显了,增强之后的类,call方法调用的时候,增加了我们定义的那个MethodInteceptor的两个方法,一个在call调用前调用,一个在call调用之后调用。

    至于,其他的方法我们着重看下:构造函数

    构造函数写的比较明显了,这里要说明的是代码增强里,添加了属性: public MethodInteceptor h;

    构造函数里,除了调用父类的构造函数外,就是把构造函数的参数里的 MethodInteceptor赋值给这个h;

    翻成代码就是:

    public Dog$$EnhancedBySimplestore$$0(MethodInteceptor h) {

      super();

      this.h = h;

    }

    然后,我们来看添加的另一个方法,另一个方法就是接口Factory的实现方法:

    也比较简单,就是新建一个增强类的实例,然后调用它的<init>方法。然后把这个对象返回。其实就是创建增强累的实例。

    翻译过来就是:

    public Dog newInstance(MethodInteceptor h){

      return new Dog$$EnhanceBySimplestore$$0(h).init();

    }

    可能翻译的不太准确,但意思就是这个意思了。

    至此我们就把Enhance增强代码做的事情,基本原理弄明白了。

    写的比较简单,看了一下Enhance的代码,但其实看了个大概已经花了一两个钟头的时间了,期间做的代码增强的事情,还是挺强的。其实核心在于对于Class类结构的熟知以及对Bcel的使用。有了这两样东西,加上耐心,把cglib的事情做掉就并不是难事了。

    再来理解下cglib的这个最简化版本的内容,我们发现,其实我们把Enhance这个具体的实现类去除后,就是两个接口类。

    那么这两个接口类就比较有意思了,一个是一个返回实例类的接口:

    public Object newInstance(MethodInterceptor ih);

    把MethodInteceptor实例作为参数,构造出来一个对象。

    一个是具体的MethodInteceptor接口本身,这个接口有两个方法,一个是invokeSuper,一个是afterReturn。

    思考一下,cglib的具体做的事情无外乎就是:

    1:为增强类添加一个MethodInteceptor的属性h;

    2:为增强类添加一个以MethodInteceptor接口的实例为参数的构造函数,并将MethodInteceptor的实例赋值给1步骤创建的属性h。

    3:为增强类添加一个以MethodInteceptor接口的实例为参数的newInstance方法,这个方法里调用2步骤添加的构造函数,创建出增强累。

    4:为原始类的方法,增加增强实现。即在调用原始方法的前后,调用属性h即传入的MethodInteceptor的实例的那两个invokeSuper和afterReturn方法。

    思路,就是这么简单。把我们的MethodInteceptor的实现,增强到原始类的方法中,就可以了。借助于代码增强,和继承的特性来实现了这个方案。

    解析到这里就结束了,相信cglib的后续版本做了很多的优化和其他相关功能的添加。但最核心的这个事情应该是没什么大变动的,后续有时间再专门写一篇来对比最新的版本做了那些事情。跟现在这个版本的核心代码有什么变动。

  • 相关阅读:
    EPANET头文件解读系列4——EPANET2.H
    EPANET头文件解读系列3——TOOLKIT.H
    EPANET头文件解读系列2——ENUMSTXT.H
    EPANET头文件解读系列1——TEXT.H
    ENUMSTXT.H中的指针数组
    main函数的参数
    函数指针与指针函数
    FMDB源码阅读
    17个提升iOS开发效率的必用工具
    UIKit性能调优实战讲解
  • 原文地址:https://www.cnblogs.com/aquariusm/p/11180522.html
Copyright © 2011-2022 走看看