动态类生成 / 加载机制(更新)
前言
一般的编译是编译器编译.java文件 生成.class文件 然后JVM加载并运行.class字节码文件
反射的前提是内存中已经有了Class<T>对象 或者 通过Class.forName等方法去加载静态的.class文件 最终还是需要Class对象
那么动态生成Class对象的几种技术 JDK代理 CGLIB代理 ASM ByteBuddy Javassist 这几种技术都是内存中生成Class对象 默认都不会有.class静态文件(待确认) 其中JDK代理和CBLIB代理是基于目标接口/父类需要以某种形式被JVM加载(例如已有的.class文件进行代理 或者 目标接口/父类 已经在内存中生成) 然后通过反射调用
反射的前提是需要内存中有Class对象 不管这个Class对象是通过静态加载 或动态加载
JDK、CGLIB、ASM、ByteBuddy、Javassist 最终都可以动态在内存中生成Class对象 利用反射完成功能
反射是一种操作类,对象,方法的方式 但是内存中已经有了Class对象 不一定非要用反射 也可以直接new
CGLIB 是基于ASM
ByteBuddy 也是基于ASM 因为JDK代理和CGLIB代理基于目标接口/父类 已经在内存中生成 那么就是ByteBuddy和Javassist 是正在完全动态
JDK 动态代理
目标对象必须实现接口
1.定义接口
public interface UserService {
void doSomething();
}
目标类
public class UserServiceImpl implements UserService {
@Override
public void doSomething() {
System.out.println("执行核心业务逻辑...");
}
}
以匿名内部类的写法
package com.hrui.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * @author hrui * @date 2025/4/10 11:03 */ public class JdkProxyDemo { public static void main(String[] args) { UserService target = new UserServiceImpl(); UserService proxyInstance = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), // 类加载器 new Class[]{UserService.class}, // 接口列表 (proxy, method, args1) -> { System.out.println("before"); Object invoke = method.invoke(target, args1); System.out.println("after"); return invoke; }//调用处理器 可以以匿名内部类的写法 也可以以单独写一个类实现InvocationHandler接口 ); proxyInstance.doSomething(); } }
创建代理处理器的写法(InvocationHandler)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class LogInvocationHandler implements InvocationHandler {
private final Object target;
public LogInvocationHandler(Object target) {
this.target = target;
}@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法开始:" + method.getName());
Object result = method.invoke(target, args); // 反射调用目标方法
System.out.println("方法结束:" + method.getName());
return result;
}
}
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();// 创建代理对象
UserService proxyInstance = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
new Class[]{UserService.class}, // 接口列表
new LogInvocationHandler(target) // 调用处理器
);// 调用方法(会被代理拦截)
proxyInstance.doSomething();
}
}
可以看到并没有生成静态的.class文件
CGLIB 动态代理
代理对象会继承目标类,不需要目标类实现某接口,目标类不能是final修饰的
引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
被代理的目标类
public class UserService {
public void doSomething() {
System.out.println("执行业务逻辑");
}
}
创建方法拦截器
package com.hrui.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * CGLIB 动态代理处理器(基于继承方式实现) * 用于在调用目标类方法前后插入自定义逻辑(如日志记录) * * 原理:CGLIB 通过生成目标类的子类,重写方法插入拦截逻辑(类似 AOP) * * 注意事项: * - 被代理的类不能是 final 类 * - 被代理的方法不能是 final 或 static * - JDK 16+ 需要 JVM 参数开放模块:--add-opens java.base/java.lang=ALL-UNNAMED * * 示例用法: * UserService proxy = (UserService) new LogHandler().getInstance(UserService.class); * proxy.doSomething(); * * 输出结果: * 之前 * 执行业务 * 之后 * * @author hrui * @date 2025/4/10 16:03 */ public class LogHandler implements MethodInterceptor { /** * 创建代理对象 * * @param clazz 目标类的 Class 对象 * @return 被代理后的实例对象 */ public Object getInstance(Class<?> clazz) { Enhancer enhancer = new Enhancer(); // 创建增强器 enhancer.setSuperclass(clazz); // 设置父类(被代理的目标类) enhancer.setCallback(this); // 设置方法拦截器回调 return enhancer.create(); // 创建代理对象 } /** * 拦截方法逻辑(类似 AOP) * * @param obj 代理对象 * @param method 被调用的方法 * @param args 方法参数 * @param proxy 方法代理对象(用于调用原始方法) * @return 方法返回值(必须返回原值,否则会丢失结果) */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(); // 调用前增强 Object result = proxy.invokeSuper(obj, args); // 调用原始方法(非反射!) after(); // 调用后增强 return result; } private void before() { System.out.println("之前"); } private void after() { System.out.println("之后"); } }
调用
package com.hrui.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * @author hrui * @date 2025/4/10 15:59 */ public class CglibDemo { public static void main(String[] args) { UserService proxy = (UserService) new LogHandler().getInstance(UserService.class); proxy.doSomething(); } }
注意 JDK17中
因为 CGLIB 使用反射访问了 java.lang.ClassLoader.defineClass(...)
方法,而这个方法从 JDK 16+ 开始默认被封闭,需要手动开放访问权限。
需要添加JVM参数
--add-opens java.base/java.lang=ALL-UNNAMED
匿名内部类方式
package com.hrui.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * @author hrui * @date 2025/4/10 15:59 */ public class CglibDemo { // public static void main(String[] args) { // UserService proxy = (UserService) new LogHandler().getInstance(UserService.class); // proxy.doSomething(); // } //用匿名内部类方式 public static void main(String[] args) { // 目标类 class UserService { public void sayHello() { System.out.println("执行业务逻辑"); } } // 创建代理对象(使用匿名内部类作为拦截器) UserService proxy = (UserService) Enhancer.create( UserService.class, // 设置父类 new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxyMethod) throws Throwable { System.out.println("之前"); Object result = proxyMethod.invokeSuper(obj, args); // 调用原始方法 System.out.println("之后"); return result; } }); proxy.sayHello(); // 调用代理方法 } }
ByteBuddy
ByteBuddy 不仅仅能用来创建代理,它的能力远远超过“代理”——它是一个通用的 Java 字节码操作和生成框架。
-
基于 ASM 构建的字节码生成工具
-
支持动态创建类、增强已有类、方法拦截、注解处理等
-
API 语义化、链式调用、可读性强
-
可用于运行时 / 构建期(AOT)
添加依赖
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.11</version>
</dependency>