首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >JDK-CGLIB-反射

JDK-CGLIB-反射

原创
作者头像
lantz还在学
发布2025-11-27 10:57:50
发布2025-11-27 10:57:50
1040
举报
文章被收录于专栏:javaweb&springjavaweb&spring

JDK动态代理-CGLIB动态代理-java反射机制

JDK 动态代理和 CGLIB 动态代理有什么区别?

JDK 动态代理

基于接口的,所以要求代理类一定是有定义接口的

CGLIB

基于 ASM 字节码生成工具,通过继承的方式生成目标类的子类来实现代理类,所以要注意 final 方法

二者之间的性能会随着 JDK 版本的不同而不同

jdk6:运行次数较少时,jdk 动态代理和 cglib 差距不明显,甚至更快一些;而当调用次数增加之后,cglib 表现稍微更快一些

jdk7:运行次数较少(1,000,000)的情况下,jdk 动态代理比 cglib 快了差不多 30%;而当调用次数增加之后(50,000,000),动态代理比 cglib 快了接近 1 倍

jdk8 表现和 jdk7 基本一致

表格一览:

对比项

JDK 动态代理

CGLIB 动态代理

代理方式

基于 接口

基于 继承类(子类)

要求

必须有接口

不需要接口,但类不能是 final

底层技术

反射 + Proxy

ASM 字节码增强

性能

JDK8 以前慢;JDK9+ 优化后差距小

快(因为直接生成子类)

常用场景

Spring AOP 中代理接口

Spring AOP 中代理没有接口的类

限制

只能代理接口方法

无法代理 final 类、final 方法

JDK动态代理工作原理

  • 基于接口的代理,得有一个接口才可以用
  • 生成一个Proxy.newProxyInstance()
  • 调用方法时,会走到InvocationHandler.invoke()
  • invoke()中增强逻辑(日志、事务、权限)
  • 再调用目标方法

JDK 动态代理的核心是:

  1. Proxy.newProxyInstance(...) —— 通过反射创建代理对象
  2. InvocationHandler.invoke(...) —— 通过反射执行目标方法

JDK动态代理会在运行的时候为接口生成一个代理类,当调用代理对象的时候,本质是反射调用目标方法

代码示例

定义一个接口:

代码语言:java
复制
public interface Service {
    void perform();
}

接口实现:

代码语言:java
复制
public class ServiceImpl implements Service{
    @Override
    public void perform() {
        System.out.println("接口实现1");
    }
}

基于InvocationHandler实现

代码语言:java
复制
public class ServiceInvocationHandler implements InvocationHandler {
    private final Object target;

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

    // 可以添加增强逻辑,在本invoke方法中添加
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invoke");
        Object result = method.invoke(target, args); // 反射调用
        System.out.println("After method invoke");
        return result;
    }
}

动态代理测试:

代码语言:java
复制
public class DynamicProxyDemo {
    public static void main(String[] args) {
        Service target = new ServiceImpl();
        Service proxy = (Service) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new ServiceInvocationHandler(target)
        );
        proxy.perform();
    }
}

使用JDK proxy代理对象,必须基于接口

CGLIB动态代理工作原理

  • 使用ASM生成目标的子类
  • 方法调用被MethodInterceptor.intercept()拦截
  • intercept中增强逻辑
  • 再反射调用原方法

CGLIB 是生成子类 → 不能代理 final 类和 final 方法。

代码演示

Service

代码语言:java
复制
public class Service {
    public void perform() {
        System.out.println("lantz.com");
    }
}

ServiceMethodInterceptor类基于MethodInterceptor接口实现

代码语言:java
复制
public class ServiceMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method invoke");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method invoke");
        return result;
    }
}

通过proxy.invokeSuper() 调用父类(即真实对象)逻辑,体现了 CGLIB 是基于“继承”

Cglib动态代理测试:

代码语言:java
复制
public class CglibDynamicProxyDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service.class);
        enhancer.setCallback(new ServiceMethodInterceptor());

        Service proxy = (Service) enhancer.create();
        proxy.perform();
    }
}

结果:

代码语言:tex
复制
Before method invoke
lantz.com
After method invoke

Spring AOP 选择原则

条件

使用代理

bean 有接口

JDK 动态代理

bean 没有接口

CGLIB 动态代理

开启 proxy-target-class=true

强制使用 CGLIB

什么是Java反射机制?

Java 的反射机制是指在运行时获取类(Class)的结构信息(如方法、字段、构造函数)并操作对象的一种机制。

反射 = 运行时查看 + 运行时修改 + 运行时调用

如何应用反射?

反射机制提供了在运行时动态创建对象、调用方法、访问字段等功能,而无需在编译时知道这些类的具体信息

基本概念

Class 类:反射机制的核心,通过 Class 类的实例可以获取类的各种信息

反射机制的优点

  • 可以动态获取类的信息,不需要在编译时就知道类的信息
  • 可以动态创建信息,不需要在编译时就知道对象的类型
  • 可以动态调用对象的属性和方法,在运行时动态地改变对象的行为

反射的最佳实践

限制访问

尽量避免过度依赖反射,尤其是在性能关键的代码中,因为它设计动态代理和方法调用

使用缓存

缓存反射获取的类、方法、字段等信息,减少反射操作的频率

遵循设计原则

在设计系统时,尽量使用更稳定和易于维护的设计方案,只有在确实需要时才使用反射

反射的使用

1)获取Class对象

获取类的名称、父类、接口等信息

代码语言:java
复制
Class<?> clazz = Class.forName("com.mianshiya.MyClass");
// 或者
Class<?> clazz = MyClass.class;
// 或者
Class<?> clazz = obj.getClass();

2)创建对象

通过clazz.newInstance()或者constructor.newInstance()创建对象

代码语言:java
复制
Object obj = clazz.newInstance(); // 已过时
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

3)访问字段

通过Field获取类的字段和设置字段信息

代码语言:java
复制
Field field = clazz.getField("myField");
field.setAccessible(true); // 允许访问 private 字段
Object value = field.get(obj);
field.set(obj, newValue);

4)调用方法

通过Method类调用对象的方法

代码语言:java
复制
Method method = clazz.getMethod("myMethod", String.class);
Object result = method.invoke(obj, "param");

The end……

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JDK动态代理-CGLIB动态代理-java反射机制
    • JDK 动态代理和 CGLIB 动态代理有什么区别?
      • JDK 动态代理
      • CGLIB
    • JDK动态代理工作原理
      • 代码示例
    • CGLIB动态代理工作原理
      • 代码演示
  • Spring AOP 选择原则
  • 什么是Java反射机制?
    • 如何应用反射?
    • 基本概念
      • 反射机制的优点
    • 反射的最佳实践
      • 限制访问
      • 使用缓存
      • 遵循设计原则
    • 反射的使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档