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