Java-JDK动态代理与CGLIB动态代理

JDK动态代理与CGLIB动态代理

本篇文章是学习了Guide哥的开源图书中的JDK动态代理和CGLIB动态代理后,结合自己的理解所写的.Guide哥原文请点我.

JDK动态代理在MyBatis中的应用可以查看文章:MyBatis入门-Mapper接口动态代理

使用CGLIB时,需要在pom中引入依赖:

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

JDK动态代理

要使用JDK动态代理必须要知道有两个类:

  • java.lang.reflect.InvocationHandler:用来增强我们的被代理对象
  • java.lang.reflect.Proxy:用来创建代理对象

Proxy创建代理对象最常用的方法是newProxyInstance.其中的参数:

  • ClassLoader loader:被代理类的加载器,将会用来初始化被代理对象
  • Class<?>[] interfaces:被代理类实现的接口列表
  • InvocationHandler h:增强的操作实现类
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{}

InvocationHandler接口中的invoke方法如下,其中的参数:

  • Object proxy:被代理的对象
  • Method method:代理对象执行的方法
  • Object[] args:代理对象执行的方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

当我们想要增强某一个类时,就需要创建一个以其为成员变量的InvocationHandler接口实现类,并在invoke方法中定义我们自己的增强实现.

实现步骤

  1. 定义一个接口及其实现类;
  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

CGLIB动态代理

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。

为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

使用CGLIB进行动态代理必须要知道的有两个类:

  • net.sf.cglib.proxy.Enhancer:增强类,用来创建代理对象
  • net.sf.cglib.proxy.MethodInterceptor:方法拦截器接口,用来实现增强的操作

MethodInterceptor类中重写的intercept方法,其中的参数:

  • Object obj:增强的对象
  • java.lang.reflect.Method method:拦截的方法
  • Object[] args:拦截方法的参数
  • MethodProxy proxy:用来调用原始方法
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;

实现步骤

  1. 定义一个类;
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
  3. 通过 Enhancer 类的 create()创建代理类;

测试

EmailService

public interface EmailService {
    String sendEmail(String body);
}

EmailServiceImpl

public class EmailServiceImpl implements EmailService {
    @Override
    public String sendEmail(String body) {
        Random random = new Random();
        try {
            // 模拟业务操作
            TimeUnit.SECONDS.sleep(random.nextInt(10));
            System.out.println("邮件发送成功....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return body;
    }
}

JdkEmailInvokeHandler

public class JdkEmailInvokeHandler implements InvocationHandler {

    private final EmailService emailService;

    public JdkEmailInvokeHandler(EmailService emailService) {
        this.emailService = emailService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 进入代理方法内部,自定义增强实现
        System.out.println("JDK动态代理.....检查邮件服务器....");
        Object invoke = method.invoke(emailService, args);
        System.out.println("JDK动态代理.....邮件发送成功记录日志....");
        return invoke;
    }
}

CglibEmailMethodInterceptor

public class CglibEmailMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGLIB.....邮件服务器检查...");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("CGLIB.....邮件发送成功日志记录");
        return invokeSuper;
    }
}

测试类

public class TestG {
    public static void main(String[] args) {
        // JDK动态代理测试
        EmailService emailService = new EmailServiceImpl();
        JdkEmailInvokeHandler jdkEmailInvokeHandler = new JdkEmailInvokeHandler(emailService);
        EmailService jdkEmailService = (EmailService)Proxy.newProxyInstance(EmailServiceImpl.class.getClassLoader(),
                new Class[]{EmailService.class},
                jdkEmailInvokeHandler);
        jdkEmailService.sendEmail("JDK邮件发送....");
        // CGLIB动态代理测试
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(EmailServiceImpl.class.getClassLoader());
        enhancer.setSuperclass(EmailServiceImpl.class);
        CglibEmailMethodInterceptor cglibEmailMethodInterceptor = new CglibEmailMethodInterceptor();
        enhancer.setCallback(cglibEmailMethodInterceptor);
        EmailService cglibEmailService = (EmailService) enhancer.create();
        cglibEmailService.sendEmail("CGLIB邮件发送....");
    }
}

输出结果

JDK动态代理.....检查邮件服务器....
邮件发送成功....
JDK动态代理.....邮件发送成功记录日志....
CGLIB.....邮件服务器检查...
邮件发送成功....
CGLIB.....邮件发送成功日志记录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值