class文件简介及加载

在运行期的代码中生成二进制字节码

Java字节码生成开源框架介绍--ASM:

Java字节码生成开源框架介绍--Javassist:

通过JD-gui反编译工具打开Programmer.class 可以看到以下代码:

代理的基本构成:

上面的这幅代理结构图是典型的静态的代理模式:

当在代码阶段规定这种代理关系,Proxy类通过编译器编译成class文件,当系统运行时,此class已经存在了。这种静态的代理模式固然在访问无法访问的资源,增强现有的接口业务功能方面有很大的优点,但是大量使用这种静态代理,会使我们系统内的类的规模增大,并且不易维护;并且由于Proxy和RealSubject的功能 本质上是相同的,Proxy只是起到了中介的作用,这种代理在系统中的存在,导致系统结构比较臃肿和松散。

由于我们现在不希望静态地有StationProxy类存在,希望在代码中,动态生成器二进制代码,加载进来。为此,使用Javassist开源框架,在代码中动态地生成StationProxy的字节码:

上述代码执行过后,会产生StationProxy的字节码,并且用生成字节码加载如内存创建对象,调用inquire()方法,会得到以下结果:

通过上面动态生成的代码,我们发现,其实现相当地麻烦在创造的过程中,含有太多的业务代码。我们使用上述创建Proxy代理类的方式的初衷是减少系统代码的冗杂度,但是上述做法却增加了在动态创建代理类过程中的复杂度:手动地创建了太多的业务代码,并且封装性也不够,完全不具有可拓展性和通用性。如果某个代理类的一些业务逻辑非常复杂,上述的动态创建代理的方式是非常不可取的!

InvocationHandler角色的由来

其中JDK中提供的创建动态代理的机制,是以a 这种思路设计的,而cglib 则是以b思路设计的。

JDK的动态代理创建机制----通过接口

JDK通过 java.lang.reflect.Proxy包来支持动态代理,一般情况下,我们使用下面的newProxyInstance方法

static ObjectnewProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
          返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

而对于InvocationHandler,我们需要实现下列的invoke方法:

在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler 的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。

 Objectinvoke(Object proxy,Method method,Object[] args)
          在代理实例上处理方法调用并返回结果。

讲的有点抽象,下面通过一个实例来演示一下吧:

cglib 生成动态代理类的机制----通过类继承:

一个有趣的例子:定义一个Programmer类,一个Hacker类

  1. package samples;
  2. /**
  3. * 程序猿类
  4. * @author louluan
  5. */
  6. public class Programmer {
  7. public void code()
  8. {
  9. System.out.println("I'm a Programmer,Just Coding.....");
  10. }
  11. }
  1. package samples;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.MethodInterceptor;
  4. import net.sf.cglib.proxy.MethodProxy;
  5. /*
  6. * 实现了方法拦截器接口
  7. */
  8. public class Hacker implements MethodInterceptor {
  9. @Override
  10. public Object intercept(Object obj, Method method, Object[] args,
  11. MethodProxy proxy) throws Throwable {
  12. System.out.println("**** I am a hacker,Let's see what the poor programmer is doing Now...");
  13. proxy.invokeSuper(obj, args);
  14. System.out.println("****  Oh,what a poor programmer.....");
  15. return null;
  16. }
  17. }
  1. package samples;
  2. import net.sf.cglib.proxy.Enhancer;
  3. public class Test {
  4. public static void main(String[] args) {
  5. Programmer progammer = new Programmer();
  6. Hacker hacker = new Hacker();
  7. //cglib 中加强器,用来创建动态代理
  8. Enhancer enhancer = new Enhancer();
  9. //设置要创建动态代理的类
  10. enhancer.setSuperclass(progammer.getClass());
  11. // 设置回调,这里相当于是对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
  12. enhancer.setCallback(hacker);
  13. Programmer proxy =(Programmer)enhancer.create();
  14. proxy.code();
  15. }
  16. }

程序执行结果:
Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)-LMLPHP

让我们看看通过cglib生成的class文件内容:

  1. package samples;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.core.ReflectUtils;
  4. import net.sf.cglib.core.Signature;
  5. import net.sf.cglib.proxy.Callback;
  6. import net.sf.cglib.proxy.Factory;
  7. import net.sf.cglib.proxy.MethodInterceptor;
  8. import net.sf.cglib.proxy.MethodProxy;
  9. public class Programmer
    EnhancerByCGLIB

    fa7aa2cd extends Programmer

  10. implements Factory
  11. {
  12. //......省略
  13. private MethodInterceptor CGLIB$CALLBACK_0;  // Enchaner传入的methodInterceptor
  14. // ....省略
  15. public final void code()
  16. {
  17. MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
  18. if (tmp4_1 == null)
  19. {
  20. tmp4_1;
  21. CGLIB$BIND_CALLBACKS(this);//若callback 不为空,则调用methodInterceptor 的intercept()方法
  22. }
  23. if (this.CGLIB$CALLBACK_0 != null)
  24. return;
  25. //如果没有设置callback回调函数,则默认执行父类的方法
  26. super.code();
  27. }
  28. //....后续省略
  29. }
04-16 14:44
查看更多