Java 动态代理和CGlib

作者: 环球探测 | 来源:发表于2016-04-04 23:33 被阅读264次

参考书目:
《从零开始写Java Web框架》黄勇

1. 代理模式

代理的思想是使用一个代理类封装一个具有某个方法的类,当我们需要在外部使用这个方法的时候,我们通过调用代理类实现。这样,我们可以在代理类里面定义一些我们想要在这个方法前面或后面做的事。下面是一个简单的例子:
Java
//定义接口
public interface Hello{
void say(String name);
}

//定义实现类
public class HelloImpl implements Hello{
public void say(String name){
System.out.println("hello , " +name);
}
}

//定义代理
public class HelloProxy implements Hello{
private Hello hello;

public HelloProxy(){
this.hello = new HelloImpl();
}

public void say(String name){
before();
hello.say(name);
after();
}

public void before(){
//do something
}

public void after(){
//do something
}
}

//使用
Hello helloProxy = new HelloProxy();
helloProxy.say("captain !")

### 2.动态代理
很容易看出,我们在上一个部分中实现的 HelloProxy类只能对HelloImpl进行代理,而当我们有多个接口和实现类需要代理的时候,需要对每个接口的实现编写一个代理类。这显然是不够优雅的做法。更好的解决方法是使用“动态代理”。所谓动态代理,也就是可以动态设置它所代理的类的代理。JDK本身为我们实现动态代理提供了两个类:InvocationHandler和Proxy。InvocationHandler源码如下:
```Java```
//InvocationHandler 源码
package java.lang.reflect;
public interface InvocationHandler {
  //方法调用函数
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

Proxy源码较复杂,这里就不将所有代码列出来了。我们只看Proxy类的一个方法,具体实现先不管了。
Java
//根据一个类的ClassLoader, 该类实现的所有接口和一个InvocationHandler生成一个代理该类的对象(这个对象实现了该类所有的接口)
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
... //具体实现参照源码
}

接下来我们使用这两个类重写Hello的代理:
```Java```
public class MyHandler implements InvocationHandler{
  private Object target;
  public MyHandler(Object target){
    this.target = target;
  }
  @override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    before();
    Object result = method.invoke(target, args);
    after();
    return result;
  }
  ...
}
// 使用
Hello hello = new HelloImpl();
MyHandler handler = new MyHandler(hello);
Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(),hello.getClass().getInterfaces(),handler);
helloProxy.say("Captain!");

3.CGlib动态代理

在上一部分,我们使用JDK内置的两个类来完成了一个动态代理的实现,但是这个实现仍然有很严重的限制,那就是它只能为实现了接口的类进行代理。假如我们要代理任意的类,更好的选择是使用CGLib库。CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。
通过maven引入最新版的gclib:
xml
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.1</version>
</dependency>

接下来我们使用CGlib提供的相关API来实现Hello的代理:
```Java```
public class CGLibProxy implements MethodInterceptor{
  public <T> T getProxy(Class<T> cls){
    return (T)Enhancer.create(cls,this);
  }
  
  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable{
    before();
    Object result = proxy.invokeSuper(obj, args);
    after();
    return result;
  }
  ...
}

//使用
CGLibProxy cgLibProxy = new CGLibProxy();
Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class);
helloProxy.say("Captain!");

相关文章

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • 保存java 动态代理生成的字节码文件

    保存java 动态代理生成的字节码文件 在Java中,常用的动态代理技术有JDK的动态代理和cglib动态代理,不...

  • 动态代理的两种方式

    静态代理就不说了,基本用到的都是动态代理。 Java中动态代理有JDK动态代理和CGLIB动态代理。 JDK代理的...

  • 源码基础 -- 动态代理(2)

    再看java动态代理之Cglib动态代理,早期大家选择Cglib主要是因为Cglib底层采用ASM字节码生成框架,...

  • Java 代理

    静态代理 动态代理 JDK 提供的Proxy CGLib cglib | GitHub 参考文章 Java的三种代理模式

  • Java 动态代理

    前言 关于动态代理 JDK动态代理 CGLIB动态代理 区别 java动态代理是利用反射机制生成一个实现代理接口的...

  • Java面试之Java基础下册(含答案)

    15.动态代理与cglib实现的区别。 动态代理有两种实现方式,分别是:jdk动态代理和cglib动态代理 jdk...

  • 源码解析--JDK动态代理

    动态代理的两种方式JDK动态代理和cglib动态代理在上一篇中动态代理jdk和cglib的区别已经通过实例做了比较...

  • Spring AOP

    本文主要是解析Spring AOP的运作流程。上次讲到Java中的两种动态代理技术:JDK动态代理和CGLIB动态...

  • Jdk动态代理 底层源码分析

    前言 java动态代理主要有2种,Jdk动态代理、Cglib动态代理,本文主要讲解Jdk动态代理的使用、运行机制、...

网友评论

    本文标题:Java 动态代理和CGlib

    本文链接:https://www.haomeiwen.com/subject/rufplttx.html