前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud 下使用Javassist 在类被加载之前修改字节码

Spring Cloud 下使用Javassist 在类被加载之前修改字节码

作者头像
崔认知
发布2024-06-04 09:48:50
1520
发布2024-06-04 09:48:50
举报
文章被收录于专栏:nobodynobody

Spring Cloud 下使用Javassist 在类被加载之前修改字节码

Spring Cloud 项目中,很多功能都是用 aop去实现的,或者直接使用Java Agent。

在两者都不能使用的情况下,我们可以考虑使用Javassist 直接操作字节码来实现。

我们需要使用Spring 的一个扩展点 ApplicationContextInitializer,在类被加载之前修改字节码,注意在Spring Cloud 环境下,一般存在父子容器,此扩展点被执行两次,需要在子容器初始化时机操作。

示例代码如下:录制随机数函数的返回值

(为了复用,抽象出一个父类)

代码语言:javascript
复制
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

import java.io.IOException;
import java.util.*;

/**
 * @author: 
 * date: 2088/15/19
 */
public abstract class BaseApplicationContextInitializer implements ApplicationContextInitializer {
 protected Logger log = LoggerFactory.getLogger(getClass());

 private static volatile int initialized = 0;

 @Override
 public void initialize(ConfigurableApplicationContext applicationContext) {
 Optional<String> optional = Arrays.stream(applicationContext.getEnvironment().getActiveProfiles())
 .filter(t -> "online".equals(t) || "unittest".equals(t))
 .findFirst();

 if (optional.isPresent()) {
 return;
 }

 if (initialized == 1) {
 log.info(getClass().getSimpleName() + " begin");
 try {
 doJavassist();
 log.info(getClass().getSimpleName() + " end");
 } catch (Throwable e) {
 log.error(getClass().getSimpleName(), e);
 throw new RuntimeException(e);
 }

 initialized += 1;
 }
 if (initialized == 0) {
 initialized += 1;
 }
 }

 protected abstract void doJavassist() throws Exception;


}
代码语言:javascript
复制


import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

import java.util.Random;

/**
 * @author: 
 * date: 2088/15/19
 */
public class RandomStringUtilsAop extends BaseApplicationContextInitializer {

 @Override
 protected void doJavassist() throws Exception {
 ClassPool classPool = ClassPool.getDefault();

 classPool.importPackage("java.util.Random");

 CtClass randomStringUtilsClass = classPool.get("org.apache.commons.lang3.RandomStringUtils");

 CtClass[] paramsClasses = new CtClass[]{
 classPool.get(int.class.getName()),
 classPool.get(int.class.getName()),
 classPool.get(int.class.getName()),
 classPool.get(boolean.class.getName()),
 classPool.get(boolean.class.getName()),
 classPool.get(char[].class.getName()),
 classPool.get(Random.class.getName())
 };

 CtMethod ctMethod = randomStringUtilsClass.getDeclaredMethod("random", paramsClasses);
 CtMethod srcInvoke = CtNewMethod.copy(ctMethod, randomStringUtilsClass, null);
 srcInvoke.setName("srcInvoke");
 randomStringUtilsClass.addMethod(srcInvoke);

 ctMethod.setBody("{\n" +
 " String className = \"org.apache.commons.lang3.RandomStringUtils\";\n" +
 " String methodName = \"random\";\n" +
 " String result = null;\n" +
 " Throwable ex = null;\n" +
 "\n" +
 " try {\n" +
 " result = srcInvoke($$);\n" +
 " } catch (RuntimeException e) {\n" +
 " ex = e;\n" +
 " }\n" +
 "\n" +
 " RecordUtils.record(className, methodName, result, ex);\n" +
 " if (ex != null) {\n" +
 " throw ex;\n" +
 " }\n" +
 " return result;\n" +
 " }");

 randomStringUtilsClass.toClass();//加载修改后的类,注意:必须保证调用前此类未加载
 if (randomStringUtilsClass.isFrozen()) {
 randomStringUtilsClass.defrost();
 }
 }



}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档