深圳燃气公司客服网站优化的方法与技巧
前言
一般的编译是编译器编译.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 方法返回值(必须返回原值,否则会丢失结果)*/@Overridepublic 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() {@Overridepublic 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>