动态代理最全详解(实现方式及使用场景)

动态代理最全详解(实现方式及使用场景)-mikechen

动态代理广泛应用于Spring AOPRPC框架等场景,而且Java面试经常问,下面我就全面来详解动态代理@mikechen

动态代理定义

动态代理是一种在运行时动态创建代理对象的方式,与静态代理相比,它可以更加灵活地生成代理对象,避免了在编译时就需要确定代理对象的类型的限制。

 

为什么需要动态代理

按照代理的创建时期,代理类可以分为两种:

动态代理最全详解(实现方式及使用场景)-mikechen

静态代理是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,但缺点是需要编写大量的代理类源代码。

所以,动态代理就出现了,它在运行期间动态生成代理对象,无需手动编写代理类,可以减少代码冗余和维护成本。

 

动态代理使用场景

动态代理常用于:框架中的横向切面Spring AOP实现,比如:添加日志、安全控制、事务控制等。

动态代理最全详解(实现方式及使用场景)-mikechen

动态代理在不改变原有代码的基础上对其进行增强的目的,此外,动态代理还可以用于解决远程方法调用RPC等场景。

 

动态代理的实现方式

Java中实现动态代理主要有两种方式:基于JDK的动态代理和基于CGLIB动态代理

1.JDK动态代理

基于JDK的动态代理使用Java自带的java.lang.reflect.Proxy类来实现。

1)首先,我们需要定义一个接口

public interface UserService {
    void save();
}

 

2)然后,我们定义一个实现该接口的类

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("save user");
    }
}

 

3)接下来,我们需要编写一个InvocationHandler的实现类

该类需要实现invoke方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserServiceProxy implements InvocationHandler {
    private Object target;

    public UserServiceProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke method");
        Object result = method.invoke(target, args);
        System.out.println("after invoke method");
        return result;
    }
}

 

4)调用接口

import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new UserServiceProxy(userService)
        );
        proxy.save();
    }
}

JDK动态代理的原理是在运行时通过反射机制动态创建一个代理类,然后在运行时将需要代理的目标对象的引用传入代理类中,再通过代理类调用目标对象的方法。

 

2.CGLib动态代理

基于CGLIB动态代理则是使用CGLIB(Code Generation Library)来动态生成代理类。

相较于JDK动态代理只能代理接口,CGLib可以代理任意的普通类,因此它也被称为是一个高性能的代理框架。

CGLIB动态代理的实现主要依赖于ASM这个开源的Java字节码编辑器和解析器。

如下图所示:

动态代理最全详解(实现方式及使用场景)-mikechen

CGLib动态代理的基本原理如下:

  1. 通过目标类的子类来作为代理类,即生成一个目标类的子类;
  2. 在代理类中实现对目标类方法的调用,并添加增强逻辑;
  3. 将代理类的字节码加载到JVM中,并返回代理类实例。

CGLib动态代理的优点是:

  1. 相对于JDK动态代理,它可以代理任意的普通类;
  2. 生成代理类的速度相对较快,因为CGLib是直接对字节码进行操作,而不是像JDK动态代理那样需要通过反射来获取和调用目标方法。

CGLib动态代理的缺点是:

  1. 由于它是通过继承目标类来实现代理的,因此如果目标类被final修饰,则无法被代理;
  2. 由于它是在内存中构建代理类的字节码并加载类,因此对内存的消耗比较大。

以上就是动态代理详解,更多内容请查看:JDK动态代理详解(实现原理及使用示例)

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

👇阅读更多mikechen架构文章👇

阿里架构 |双11秒杀 |分布式架构 |负载均衡 |单点登录 |微服务 |云原生 |高并发 |架构师

以上

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

评论交流
    说说你的看法