cglib的最第一版本干了什么?

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

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

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

github上cglib的版本最先的是面试

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

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

先看下代码:ide

/*
 * 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的后续版本作了不少的优化和其余相关功能的添加。但最核心的这个事情应该是没什么大变更的,后续有时间再专门写一篇来对比最新的版本作了那些事情。跟如今这个版本的核心代码有什么变更。

相关文章
相关标签/搜索