美文网首页
Java动态代理 CGLib 与 JDK Proxy

Java动态代理 CGLib 与 JDK Proxy

作者: DoubleFooker | 来源:发表于2019-07-09 16:00 被阅读0次

JDK动态代理

动态代理区别于静态代理,代理类在运行时生成。JDK 提供InvocationHandler接口和Proxy类实现动态代理。

由于Proxy生成代理类方法

Proxy. newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h);需要传入带实现的接口方法interfaces,JDK动态代理需要实现接口才能实现。

代码实现:

定义接口

public interface Subject{
    void doMethod();
}

实现类:

public class RealSubject implements Subject{
    public void doMethod(){
        System.out.println("JDK Proxy Do Method Real!");
    }
}

代理类:

public class ProxyService implements InvocationHandler{
   private Subject subject;
   public Object getInstance(Subject subject){
       this.subject=subject;
       Class<?> clazz=subjcet.getClass();
       return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
   }
    
        @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable       {
         System.out.println("JDK Proxy Do Before!");
        method.invoke(this.subject,args);
         System.out.println("JDK Proxy Do After!");
        return null;
    }
}

测试类:

    public static void main(String[] args) {
        Subject subject= (Subject) new ProxyService().getInstance(new RealSubject());
        subject.doMethod();
        
         /**
         * 保存jdk动态生成代码查看
         */
        byte[] batyes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Subject.class});
        try (FileOutputStream out = new FileOutputStream("E://$Proxy0.class")) {
            out.write(batyes);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }

测试输出:

JDK Proxy Do Before!
JDK Proxy Do Method Real!
JDK Proxy Do After!

代理生成源码,JDK动态代理生成的类以$Proxy0命名。具体代码生成的过程请查看Proxy.newProxyInstance源码。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.ognice.proxy.jdkproxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//实现了 Subject接口
public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    // 目标方法
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
       //...
    }

    public final String toString() throws  {
      //...
    }
// 目标方法,h为传入的ProxyService,m3由静态代码块初始化
    public final void doMethod() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
       //...
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            // 通过反射获取目标实现方法m3
            m3 = Class.forName("com.ognice.proxy.jdkproxy.Subject").getMethod("doMethod");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

CGLIB动态代理

JDK动态代理需要实现接口才能实现,cglib对JDK动态代理的补充,但对于final类无法实现代理,因为cglib实现动态生成被代理类的子类形式。cglibt代理类通过实现MethodInterceptor接口实现代理逻辑

引入依赖

      <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.7</version>
        </dependency>

被代理类

public class TargetService{
    public void doMethod(){
        System.out.printIn("Real Method!")
    }
}

代理类实现MethodInterceptor接口


public class ProxyService implements MethodInterceptor{
     public Object getInstance(Class<?> clazz) {
         //代理类生成
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
         // 配置回调
        enhancer.setCallback(this);
        return enhancer.create();
    }
    /**
     * 重写方法拦截在方法前和方法后加入业务
     * Object obj为目标对象
     * Method method为目标方法
     * Object[] params 为参数,
     * MethodProxy proxy CGlib方法代理对象
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] params,
            MethodProxy proxy) throws Throwable {
        System.out.println("CGlib Proxy Before");
        proxy.invokeSuper(obj, params);
        System.out.println("CGlib Proxy AFter");
        return result;
    }
}

测试类

    public static void main(String[] args) {
     TargetService targetService = (TargetService) new 
        ProxyService().getInstance(TargetService.class);
        targetService.doMethod();
        System.out.println(targetService.getClass());
    }

输出

CGlib Proxy Before
Real Method!
CGlib Proxy AFter
class com.ognice.proxy.cglibproxy.TargetService$$EnhancerByCGLIB$$d9637b11

可以看出最终生成的TargetService实例的类为cglib动态生成的类。原理是动态生成一个类继承了被代理类,调用invokeSuper方法实现方法调用。

相关文章

网友评论

      本文标题:Java动态代理 CGLib 与 JDK Proxy

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