【Java基础】JDK动态代理&CGLIB动态代理

217 阅读3分钟

这是我参与更文挑战的第8天,活动详情查看: 更文挑战

介绍

动态代理主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情。动态代理是设计模式中代理模式的一种。

Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式 生成由 AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。 默认的策略是如果目标类是接口, 则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。

Java动态代理

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法

  @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
  • proxy : 表示代理类

  • method : 表示被代理的方法

  • args : 该方法的参数数组 (2)Proxy:动态代理类

   public static Object newProxyInstance(ClassLoader loader,
                                          Class[<?>[]](url) interfaces,
                                          InvocationHandler h)

这个静态方法返回一个代理类的实例

  • loader 类加载器
  • interfaces
  • h : 实现实现InvocationHandler接口的类的实例 动态代理类是在运行时生成的class,在生成它时你必须提供一组interface给它,然后相当于这个类实现了这些 interface。然后就可以把这个类的实例当作这些interface中的任何一个来用。在生成动态代理类的实例时必须提供一个handler,由它接管实际的工作。

动态代理步骤:

  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
  2. 创建被代理的类以及接口
  3. 通过Proxy的静态方法newProxyInstance创建一个代理
  4. 通过代理调用方法

CGLIB动态代理

CGLIB(Code Generation Library)是一个高性能开源的代码生成包,采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强,和JDK动态代理相比,它可以代理没有实现接口的类

下面的代码demo引用了UP主"子烁爱学习"的视频——Java面试必知必会.Java基础.05.动态代理(JDK/CGLIB)中的例子

静态代理

interface Speaker {
    void speak();
}

class Lawyer implements Speaker {
    ZhangSan zhangSan = new ZhangSan();

    @Override
    public void speak() {
        System.out.println("引用法律条文~~~");
        zhangSan.speak();
        System.out.println("打人是不对的!");
    }
}

class ZhangSan implements Speaker {
    @Override
    public void speak() {
        System.out.println("我老婆打我!");
    }
}
public class Test1 {
    public static void main(String[] args) {
        ZhangSan zhangSan = new ZhangSan();
        zhangSan.speak();
        Lawyer lawyer = new Lawyer();
        lawyer.speak();
    }

}

JDK动态代理

public class Test1 {
    public static void main(String[] args) {
        ZhangSan zhangSan = new ZhangSan();
        LawyerProxy lawyerProxy = new LawyerProxy(zhangSan);
        Speaker sp = (Speaker) Proxy.newProxyInstance(Test1.class.getClassLoader(), new Class[]{Speaker.class}, lawyerProxy);
        sp.speak();
    }

}

class Lawyer implements Speaker {
    ZhangSan zhangSan = new ZhangSan();

    @Override
    public void speak() {
        System.out.println("引用法律条文~~~");
        zhangSan.speak();
        System.out.println("打人是不对的!");
    }
}

class ZhangSan implements Speaker {
    @Override
    public void speak() {
        System.out.println("我老婆打我!");
    }
}
interface Speaker {
    void speak();
}


class LawyerProxy implements InvocationHandler {
    private Object obj;
    public LawyerProxy(Object obj){
        this.obj=obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,
        String name = method.getName();//得到被代理得方法名
        if (name.equals("speak")) {
            System.out.println("引用法律条文~~~");
            method.invoke(obj, args);
            System.out.println("打人是不对的!");
        }
        return null;
    }
}

CGLIB动态代理

public class Test1 {
    public static void main(String[] args) {
        LawyerInterceptor lawyerInterceptor = new LawyerInterceptor(new LiSi());
        LiSi liSi = (LiSi) Enhancer.create(LiSi.class, lawyerInterceptor);
        liSi.speak();
    }

}
class LiSi{
    public void speak(){
    }
}
//CGLIB动态代理
class LawyerInterceptor implements MethodInterceptor {
    private Object obj;
    public  LawyerInterceptor(Object obj){
        this.obj=obj;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        String name = method.getName();
        if(name.equals("speak")){
            System.out.println("引用法律条文~~~");
            method.invoke(obj, args);
            System.out.println("打人是不对的!");
        }
        return null;
    }
}