重新定义七点半,不知道你有没有听过这个梗。 我不知道这个梗最初是来源于哪里,我第一次见是在老罗的发布会,因为老罗的发布会总会有各种各样的问题,说是七点半开,从来没有准时过,所以说,“重新定义了七点半”。
前面几篇都讲了怎么去获取数据(参数、静态字段、返回值、执行时间、执行链路),或者怎么去执行方法(静态方法、获取实例调用方法)。
这篇就说一个大招,怎么在运行时去修改代码。
0、前置工作
有下面这样一个接口,获取开始时间:
package com.chengjf.snippet.spring.mvc.service;
public interface HelloService {
/**
* 获取开始时间
*
* @return
*/
String getStartTime();
}
实现是直接返回开始时间“七点半”:
package com.chengjf.snippet.spring.mvc.service.impl;
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String getStartTime() {
return "七点半";
}
}
然后整个controller调用这个getStartTime方法:
@RequestMapping("startTime")
public Object getStartTime() {
HashMap<Object, Object> objectObjectHashMap = Maps.newHashMap();
String result = helloService.getStartTime();
objectObjectHashMap.put("startTime", result);
return objectObjectHashMap;
}
返回就是说好的“七点半”:
{
"startTime": "七点半"
}
1、反编译获取代码源文件
使用arthas进入该程序的jvm。
使用jad命令进行反编译:
jad –source-only com.chengjf.snippet.spring.mvc.service.impl.HelloServiceImpl > /Users/jeff/arthas/HelloServiceImpl.java
将com.chengjf.snippet.spring.mvc.service.impl.HelloServiceImpl反编译,将反编译后的代码写入到/Users/jeff/arthas/HelloServiceImpl.java中。
2、修改代码
修改上面反编译得到的HelloServiceImpl.java,将返回值“七点半”修改为“8点”:
@Override
public String getStartTime() {
return "8点";
}
3、编译代码
使用mc命令将修改好的java文件编译成class文件:
mc /Users/jeff/arthas/HelloServiceImpl.java
这个命令会返回编译完成的class文件的路径:
Memory compiler output: /Users/jeff/Documents/code/github/java-snippet/com/chengjf/snippet/spring/mvc/service/impl/HelloServiceImpl.class Affect(row-cnt:1) cost in 1645 ms.
4、redefine
使用redefine命令,将上面编译好的class文件装载在jvm中:
redefine /Users/jeff/Documents/code/github/java-snippet/com/chengjf/snippet/spring/mvc/service/impl/HelloServiceImpl.class
这个时候,再调用controller请求这个接口,会返回修改后的开始时间:
{
"startTime": "八点"
}
最后修改于 2020-04-28