本文不提及TTL的作用,仅从源码层面分析TTL是怎么使用JavaAgent来动态代理的
依赖如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.11.4</version>
</dependency>
JavaAgent字节码方式增强
代码入口
com.alibaba.ttl.threadpool.agent.TtlAgent
使用方式
启动jar的时候,附加上参数-javaagent:/xx/transmittable-thread-local.jar(目录自己放好)
/opt/soft/jdk/jdk1.8.0_191/bin/java
-javaagent:/xx/transmittable-thread-local.jar
-jar /opt/xxx.jar
源码分析
执行步骤
第一步:解析参数(可不传),将“xx:xx”解析为Map<String, String>
常用参数:
ttl.agent.disable.inheritable.for.thread.pool:true
ttl.agent.logger:STDOUT
ttl.agent.enable.timer.task:false第二步:设置日志输出参数类型,比如STDOUT(不设置默认就是STDOUT, loggerImplType = 0)
STDOUT: 标准输出
STDERR: 标准错误输出第三步:组装JavassistTransformlet,分为三种类型如下
TtlExecutorTransformlet处理的类:ThreadPoolExecutor及其子类、ScheduledThreadPoolExecutor
TtlForkJoinTransformlet处理的类:ForkJoinTask、ForkJoinPool
默认开启。TtlTimerTaskTransformlet处理的类:仅处理TimeTask子类第四步:调用生效的时机到了
执行生效方法:inst.addTransformer(transformer, true);
TtlAgent入口premain()方法
Java中的javaAgent一般会涉及到 MANIFEST.MF配置类、premain()方法入口,下面来解析
- MANIFEST.MF配置如下:
可见Premain-Class指向了com.alibaba.ttl.threadpool.agent.TtlAgent类
Manifest-Version: 1.0
Created-By: Apache Maven 3.5.4
Built-By: jerry
Build-Jdk: 11.0.1
Boot-Class-Path: transmittable-thread-local-2.10.2.jar
Can-Redefine-Classes: false
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: false
Premain-Class: com.alibaba.ttl.threadpool.agent.TtlAgent
接来下解析TllAgent.java入口类,其premain()方法如下
/** TTL javaAgent字节码增强premain入口类 **/
public static void premain(String agentArgs, @NonNull Instrumentation inst) {
// 第一步:解析参数(可不传),将“xx:xx”解析为Map<String, String>
// 常用参数:ttl.agent.disable.inheritable.for.thread.pool:true
// ttl.agent.logger:STDOUT
// ttl.agent.enable.timer.task:false
kvs = splitCommaColonStringToKV(agentArgs);
// 第二步:设置日志输出参数类型,比如STDOUT(不设置默认就是STDOUT, loggerImplType = 0)
// - STDOUT: 标准输出
// - STDERR: 标准错误输出
Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(kvs));
final Logger logger = Logger.getLogger(TtlAgent.class);
try {
logger.info("[TtlAgent.premain] begin, agentArgs: " + agentArgs + ", Instrumentation: " + inst);
// 获取是否开启 "关闭继承" 的能力,不传默认返回false
final boolean disableInheritableForThreadPool = isDisableInheritableForThreadPool();
// 第三步:组装JavassistTransformlet
final List<JavassistTransformlet> transformletList = new ArrayList<JavassistTransformlet>();
// TtlExecutorTransformlet处理的类:ThreadPoolExecutor及其子类、ScheduledThreadPoolExecutor
transformletList.add(new TtlExecutorTransformlet(disableInheritableForThreadPool));
// TtlForkJoinTransformlet处理的类:ForkJoinTask、ForkJoinPool
transformletList.add(new TtlForkJoinTransformlet(disableInheritableForThreadPool));
// 默认开启。TtlTimerTaskTransformlet处理的类:仅处理TimeTask子类
if (isEnableTimerTask()) transformletList.add(new TtlTimerTaskTransformlet());
// 第四步:调用生效的时机到了
final ClassFileTransformer transformer = new TtlTransformer(transformletList);
// -- 调用到了这里,最终会调用到TtlTransformer#transform()方法
// -- 备注:TtlTransformer继承了ClassFileTransformer
inst.addTransformer(transformer, true);
logger.info("[TtlAgent.premain] addTransformer " + transformer.getClass() + " success");
logger.info("[TtlAgent.premain] end");
ttlAgentLoaded = true;
} catch (Exception e) {
String msg = "Fail to load TtlAgent , cause: " + e.toString();
logger.log(Level.SEVERE, msg, e);
throw new IllegalStateException(msg, e);
}
}
接下来解析上面几个步骤~~~
第一步:解析参数(可不传),将“xx:xx”解析为Map<String, String>
- 入口:TtlAgent#premain() -> splitCommaColonStringToKV()
kvs = splitCommaColonStringToKV(agentArgs);
- 具体解析
/**
* 将创建来的字符串参数解析成map
* eg:ttl.agent.disable.inheritable.for.thread.pool:true 解析成 Map{"ttl.agent.disable.inheritable.for.thread.pool":"true"}
* Split to {@code json} like String({@code "k1:v1,k2:v2"}) to KV map({@code "k1"->"v1", "k2"->"v2"}).
*/
static Map<String, String> splitCommaColonStringToKV(@Nullable String commaColonString) {
Map<String, String> ret = new HashMap<String, String>();
if (commaColonString == null || commaColonString.trim().length() == 0) return ret;
final String[] splitKvArray = commaColonString.trim().split("\\s*,\\s*");
for (String kvString : splitKvArray) {
final String[] kv = kvString.trim().split("\\s*:\\s*");
if (kv.length == 0) continue;
if (kv.length == 1) ret.put(kv[0], "");
else ret.put(kv[0], kv[1]);
}
return ret;
}
第二步:设置日志输出参数类型,比如STDOUT(不设置默认就是STDOUT, loggerImplType = 0)
- 入口:TtlAgent#premain() -> getLogImplTypeFromAgentArgs()
/** 入口类 **/
public static void premain(String agentArgs, @NonNull Instrumentation inst) {
....
// 设置参数类型,比如STDOUT(不设置默认就是STDOUT, loggerImplType = 0)
// - STDOUT: 标准输出
// - STDERR: 标准错误输出
Logger.setLoggerImplType(getLogImplTypeFromAgentArgs(kvs));
final Logger logger = Logger.getLogger(TtlAgent.class);
....
}
private static String getLogImplTypeFromAgentArgs(@NonNull final Map<String, String> kvs) {
return kvs.get(Logger.TTL_AGENT_LOGGER_KEY);
}
/**
* eg:STDOUT
*/
public static void setLoggerImplType(String type) {
// 用loggerImplType记录已设置了
if (loggerImplType != -1) {
throw new IllegalStateException("TTL logger implementation type is already set! type = " + loggerImplType);
}
// 不设置,默认模式就是STDOUT, loggerImplType = 0
if (STDERR.equalsIgnoreCase(type)) loggerImplType = 0;
else if (STDOUT.equalsIgnoreCase(type)) loggerImplType = 1;
else loggerImplType = 0;
}
第三步(重点):组装JavassistTransformlet,分为三种类型如下
主要分为三个JavassistTransformlet如下
TtlExecutorTransformlet处理的类:ThreadPoolExecutor及其子类、ScheduledThreadPoolExecutor
TtlForkJoinTransformlet处理的类:ForkJoinTask、ForkJoinPool
默认开启。TtlTimerTaskTransformlet处理的类:仅处理TimeTask子类
- 入口:TtlAgent#premain() ->
/** 入口类 **/
public static void premain(String agentArgs, @NonNull Instrumentation inst) {
....
// JavassistTransformlet用于转换
final List<JavassistTransformlet> transformletList = new ArrayList<JavassistTransformlet>();
// TtlExecutorTransformlet处理的类:ThreadPoolExecutor及其子类、ScheduledThreadPoolExecutor
transformletList.add(new TtlExecutorTransformlet(disableInheritableForThreadPool));
// TtlForkJoinTransformlet处理的类:ForkJoinTask、ForkJoinPool
transformletList.add(new TtlForkJoinTransformlet(disableInheritableForThreadPool));
// 默认开启。TtlTimerTaskTransformlet处理的类:仅处理TimeTask子类
if (isEnableTimerTask()) transformletList.add(new TtlTimerTaskTransformlet());
....
}
- 接下来分析三个transformletList如下
-
- TtlExecutorTransformlet
@Override
public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {
if (EXECUTOR_CLASS_NAMES.contains(classInfo.getClassName())) {
// ThreadPoolExecutor、ScheduledThreadPoolExecutor
// 获取待增强的类class
final CtClass clazz = classInfo.getCtClass();
// 遍历所有的方法,目的是为了判断参数是否Runnable、Callable。然后给外层包裹TtlRunnable、TtlCallable
for (CtMethod method : clazz.getDeclaredMethods()) {
updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method);
}
// 判断是否需要禁用"继承"能力
if (disableInheritableForThreadPool)
// 禁用====================================
updateConstructorDisableInheritable(clazz);
// 标记为已修改过
classInfo.setModified();
} else {
// 非ThreadPoolExecutor、非ScheduledThreadPoolExecutor 会走到这步
final CtClass clazz = classInfo.getCtClass();
// 过滤掉 基本数据类型、数组、接口、注解
if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {
return;
}
// 过滤掉 非ThreadPoolExecutor子类数据
if (!clazz.subclassOf(clazz.getClassPool().get(THREAD_POOL_EXECUTOR_CLASS_NAME))) return;
logger.info("Transforming class " + classInfo.getClassName());
// 走到这步,说明这个类就算不是ThreadPoolExecutor,也是继承了ThreadPoolExecutor,是他的子类
// -- 尝试追加执行前后的方法,都会追加unwrapIfIsAutoWrapper()来包裹
// -- 其实就是加一个执行前后的方法beforeExecute、afterExecute
// ---- beforeExecute:用TtlRunnable.unwrap()包裹
// ---- afterExecute:直接返回Runnable,不包裹
final boolean modified = updateBeforeAndAfterExecuteMethodOfExecutorSubclass(clazz);
// 如果修改成功,就设置为 this.modified = true;
if (modified) classInfo.setModified();
}
}
-
- TtlForkJoinTransformlet
@Override
public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {
if (FORK_JOIN_TASK_CLASS_NAME.equals(classInfo.getClassName())) {
// 处理ForkJoinTask
// 这个最终来直接用try catch来拼接 备份->run()->重放 的代码
updateForkJoinTaskClass(classInfo.getCtClass());
classInfo.setModified();
} else if (disableInheritableForThreadPool && FORK_JOIN_POOL_CLASS_NAME.equals(classInfo.getClassName())) {
// 禁用"继承"能力开启 并且 类型是ForkJoinPool
updateConstructorDisableInheritable(classInfo.getCtClass());
classInfo.setModified();
}
}
-
- TtlTimerTaskTransformlet
@Override
public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {
// java.util.TimerTask不处理,直接跳过。只会处理他的子类
if (TIMER_TASK_CLASS_NAME.equals(classInfo.getClassName())) return; // No need transform TimerTask class
final CtClass clazz = classInfo.getCtClass();
// 过滤掉 基本数据类型、数组、接口、注解
if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {
return;
}
// class contains method `void run()` ?
try {
// 只处理方法包含"void run()",必须要返回void
final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]);
if (!CtClass.voidType.equals(runMethod.getReturnType())) return;
} catch (NotFoundException e) {
return;
}
// 非java.util.TimerTask子类不处理
if (!clazz.subclassOf(clazz.getClassPool().get(TIMER_TASK_CLASS_NAME))) return;
logger.info("Transforming class " + classInfo.getClassName());
// 更新代码操作
updateTimerTaskClass(clazz);
classInfo.setModified();
}