Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
阿啄debugIT
transmittable-thread-local
提交
76cb5fe8
T
transmittable-thread-local
项目概览
阿啄debugIT
/
transmittable-thread-local
与 Fork 源项目一致
从无法访问的项目Fork
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
transmittable-thread-local
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
76cb5fe8
编写于
9月 16, 2018
作者:
oldratlee
🔥
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ttl agent support TimerTask #7
上级
8a0c6064
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
137 addition
and
21 deletion
+137
-21
src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
+39
-10
src/main/java/com/alibaba/ttl/threadpool/agent/TtlTransformer.java
...java/com/alibaba/ttl/threadpool/agent/TtlTransformer.java
+2
-9
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java
...t/internal/transformlet/impl/TtlForkJoinTransformlet.java
+2
-2
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java
.../internal/transformlet/impl/TtlTimerTaskTransformlet.java
+84
-0
src/test/java/com/alibaba/ttl/threadpool/agent/TtlAgentTest.kt
...est/java/com/alibaba/ttl/threadpool/agent/TtlAgentTest.kt
+10
-0
未找到文件。
src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java
浏览文件 @
76cb5fe8
...
...
@@ -2,13 +2,14 @@ package com.alibaba.ttl.threadpool.agent;
import
com.alibaba.ttl.threadpool.agent.internal.logging.Logger
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlExecutorTransformlet
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlForkJoinTransformlet
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlTimerTaskTransformlet
;
import
java.lang.instrument.ClassFileTransformer
;
import
java.lang.instrument.Instrumentation
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.*
;
import
java.util.logging.Level
;
/**
...
...
@@ -50,8 +51,12 @@ public final class TtlAgent {
/**
* Entrance method of TTL Java Agent.
* <p>
* The log of TTL Java Agent is config by agent argument, using key {@code ttl.agent.logger}.
*
* <h2>TTL Agent configuration</h2>
* Configure TTL agent via agent arguments, format is {@code k1:v1,k2:v2}. Below is available configuration keys.
*
* <h3>The log configuration</h3>
* The log of TTL Java Agent is config by key {@code ttl.agent.logger}.
*
* <ul>
* <li>{@code ttl.agent.logger : STDERR}<br>
...
...
@@ -67,6 +72,14 @@ public final class TtlAgent {
* <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.logger:STDOUT}</li>
* </ul>
*
* <h3>Enable TimerTask class decoration</h3>
* Enable TimerTask class decoration is config by key {@code ttl.agent.enable.timer.task}. Do not enable when no configuration for this key.
* <p>
* configuration example: {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.enable.timer.task:true}
*
* <h3>Multi key configuration example</h3>
* {@code -javaagent:/path/to/transmittable-thread-local-2.x.x.jar=ttl.agent.logger:STDOUT,ttl.agent.enable.timer.task:true}
*
* @see <a href="https://docs.oracle.com/javase/10/docs/api/java/lang/instrument/package-summary.html">The mechanism for instrumentation</a>
* @see Logger
* @see Logger#TTL_AGENT_LOGGER_KEY
...
...
@@ -74,14 +87,22 @@ public final class TtlAgent {
* @see Logger#STDOUT
*/
public
static
void
premain
(
String
agentArgs
,
Instrumentation
inst
)
{
Logger
.
setLoggerImplType
(
getLogImplTypeFromAgentArgs
(
agentArgs
));
final
Map
<
String
,
String
>
kvs
=
splitCommaColonStringToKV
(
agentArgs
);
Logger
.
setLoggerImplType
(
getLogImplTypeFromAgentArgs
(
kvs
));
final
Logger
logger
=
Logger
.
getLogger
(
TtlAgent
.
class
);
try
{
logger
.
info
(
"[TtlAgent.premain] begin, agentArgs: "
+
agentArgs
+
", Instrumentation: "
+
inst
);
@SuppressWarnings
(
"unchecked"
)
ClassFileTransformer
transformer
=
new
TtlTransformer
(
TtlExecutorTransformlet
.
class
,
TtlForkJoinTransformlet
.
class
);
final
List
<
Class
<?
extends
JavassistTransformlet
>>
transformletList
=
new
ArrayList
<
Class
<?
extends
JavassistTransformlet
>>();
transformletList
.
add
(
TtlExecutorTransformlet
.
class
);
transformletList
.
add
(
TtlForkJoinTransformlet
.
class
);
if
(
enableTimerTask
(
kvs
))
{
transformletList
.
add
(
TtlTimerTaskTransformlet
.
class
);
}
final
ClassFileTransformer
transformer
=
new
TtlTransformer
(
transformletList
);
inst
.
addTransformer
(
transformer
,
true
);
logger
.
info
(
"[TtlAgent.premain] addTransformer "
+
transformer
.
getClass
()
+
" success"
);
...
...
@@ -93,9 +114,17 @@ public final class TtlAgent {
}
}
private
static
String
getLogImplTypeFromAgentArgs
(
String
agentArgs
)
{
final
Map
<
String
,
String
>
kv
=
splitCommaColonStringToKV
(
agentArgs
);
return
kv
.
get
(
Logger
.
TTL_AGENT_LOGGER_KEY
);
private
static
String
getLogImplTypeFromAgentArgs
(
final
Map
<
String
,
String
>
kvs
)
{
return
kvs
.
get
(
Logger
.
TTL_AGENT_LOGGER_KEY
);
}
private
static
final
String
TTL_AGENT_ENABLE_TIMER_TASK_KEY
=
"ttl.agent.enable.timer.task"
;
private
static
boolean
enableTimerTask
(
final
Map
<
String
,
String
>
kvs
)
{
final
boolean
hasEnableKey
=
kvs
.
containsKey
(
TTL_AGENT_ENABLE_TIMER_TASK_KEY
);
if
(!
hasEnableKey
)
return
false
;
return
!
"false"
.
equalsIgnoreCase
(
kvs
.
get
(
TTL_AGENT_ENABLE_TIMER_TASK_KEY
));
}
/**
...
...
src/main/java/com/alibaba/ttl/threadpool/agent/TtlTransformer.java
浏览文件 @
76cb5fe8
package
com.alibaba.ttl.threadpool.agent
;
import
com.alibaba.ttl.threadpool.agent.internal.logging.Logger
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet
;
import
javassist.ClassPool
;
import
javassist.CtClass
;
import
javassist.LoaderClassPath
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.lang.instrument.ClassFileTransformer
;
import
java.security.ProtectionDomain
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.logging.Level
;
import
com.alibaba.ttl.threadpool.agent.internal.logging.Logger
;
/**
* TTL {@link ClassFileTransformer} of Java Agent
*
...
...
@@ -30,8 +24,7 @@ public class TtlTransformer implements ClassFileTransformer {
private
final
List
<
JavassistTransformlet
>
transformletList
=
new
ArrayList
<
JavassistTransformlet
>();
@SuppressWarnings
(
"unchecked"
)
TtlTransformer
(
Class
<?
extends
JavassistTransformlet
>...
transformletClasses
)
throws
Exception
{
TtlTransformer
(
List
<
Class
<?
extends
JavassistTransformlet
>>
transformletClasses
)
throws
Exception
{
for
(
Class
<?
extends
JavassistTransformlet
>
transformletClass
:
transformletClasses
)
{
final
JavassistTransformlet
transformlet
=
transformletClass
.
getConstructor
().
newInstance
();
transformletList
.
add
(
transformlet
);
...
...
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlForkJoinTransformlet.java
浏览文件 @
76cb5fe8
...
...
@@ -40,7 +40,7 @@ public class TtlForkJoinTransformlet implements JavassistTransformlet {
final
String
className
=
clazz
.
getName
();
final
String
capturedFieldName
=
"captured$field$add$by$ttl"
;
final
CtField
capturedField
=
CtField
.
make
(
"private final
java.lang.
Object "
+
capturedFieldName
+
";"
,
clazz
);
final
CtField
capturedField
=
CtField
.
make
(
"private final Object "
+
capturedFieldName
+
";"
,
clazz
);
clazz
.
addField
(
capturedField
,
"com.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture();"
);
logger
.
info
(
"add new field "
+
capturedFieldName
+
" to class "
+
className
);
...
...
@@ -59,7 +59,7 @@ public class TtlForkJoinTransformlet implements JavassistTransformlet {
"if (this instanceof "
+
TTL_RECURSIVE_ACTION_CLASS_NAME
+
" || this instanceof "
+
TTL_RECURSIVE_TASK_CLASS_NAME
+
") {\n"
+
" return "
+
original_doExec_method_rename
+
"($$);\n"
+
"}\n"
+
"
java.lang.
Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay("
+
capturedFieldName
+
");\n"
+
"Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay("
+
capturedFieldName
+
");\n"
+
"try {\n"
+
" return "
+
original_doExec_method_rename
+
"($$);\n"
+
"} finally {\n"
+
...
...
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlTimerTaskTransformlet.java
0 → 100644
浏览文件 @
76cb5fe8
package
com.alibaba.ttl.threadpool.agent.internal.transformlet.impl
;
import
com.alibaba.ttl.threadpool.agent.internal.logging.Logger
;
import
com.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet
;
import
javassist.*
;
import
java.io.IOException
;
import
java.lang.reflect.Modifier
;
import
static
com
.
alibaba
.
ttl
.
threadpool
.
agent
.
internal
.
transformlet
.
impl
.
Utils
.
getCtClass
;
import
static
com
.
alibaba
.
ttl
.
threadpool
.
agent
.
internal
.
transformlet
.
impl
.
Utils
.
signatureOfMethod
;
/**
* TTL {@link JavassistTransformlet} for {@link java.util.TimerTask}.
*
* @author Jerry Lee (oldratlee at gmail dot com)
* @author wuwen5 (wuwen.55 at aliyun dot com)
* @see java.util.TimerTask
* @see java.util.Timer
* @since 2.7.0
*/
public
class
TtlTimerTaskTransformlet
implements
JavassistTransformlet
{
private
static
final
Logger
logger
=
Logger
.
getLogger
(
TtlTimerTaskTransformlet
.
class
);
private
static
final
String
TIMER_TASK_CLASS_NAME
=
"java.util.TimerTask"
;
private
static
final
String
RUN_METHOD_NAME
=
"run"
;
@Override
public
byte
[]
doTransform
(
String
className
,
byte
[]
classFileBuffer
,
ClassLoader
loader
)
throws
IOException
,
NotFoundException
,
CannotCompileException
{
if
(
TIMER_TASK_CLASS_NAME
.
equals
(
className
))
return
null
;
// No need transform TimerTask class
final
CtClass
clazz
=
getCtClass
(
classFileBuffer
,
loader
);
if
(
clazz
.
isPrimitive
()
||
clazz
.
isArray
()
||
clazz
.
isInterface
()
||
clazz
.
isAnnotation
())
{
return
null
;
}
// class contains method `void run()` ?
try
{
final
CtMethod
runMethod
=
clazz
.
getDeclaredMethod
(
RUN_METHOD_NAME
,
new
CtClass
[
0
]);
if
(!
CtClass
.
voidType
.
equals
(
runMethod
.
getReturnType
()))
{
return
null
;
}
}
catch
(
NotFoundException
e
)
{
return
null
;
}
if
(!
clazz
.
subclassOf
(
clazz
.
getClassPool
().
get
(
TIMER_TASK_CLASS_NAME
)))
{
return
null
;
}
logger
.
info
(
"Transforming class "
+
className
);
updateTimerTaskClass
(
clazz
);
return
clazz
.
toBytecode
();
}
private
void
updateTimerTaskClass
(
final
CtClass
clazz
)
throws
CannotCompileException
,
NotFoundException
{
// add new field
final
String
className
=
clazz
.
getName
();
final
String
capturedFieldName
=
"captured$field$add$by$ttl"
;
final
CtField
capturedField
=
CtField
.
make
(
"private final Object "
+
capturedFieldName
+
";"
,
clazz
);
clazz
.
addField
(
capturedField
,
"com.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture();"
);
logger
.
info
(
"add new field "
+
capturedFieldName
+
" to class "
+
className
);
final
CtMethod
runMethod
=
clazz
.
getDeclaredMethod
(
RUN_METHOD_NAME
,
new
CtClass
[
0
]);
final
CtMethod
new_runMethod
=
CtNewMethod
.
copy
(
runMethod
,
RUN_METHOD_NAME
,
clazz
,
null
);
// rename original run method, and set to private method(avoid reflect out renamed method unexpectedly)
final
String
original_run_method_rename
=
"original$run$method$renamed$by$ttl"
;
runMethod
.
setName
(
original_run_method_rename
);
runMethod
.
setModifiers
(
runMethod
.
getModifiers
()
&
~
Modifier
.
PUBLIC
/* remove public */
|
Modifier
.
PRIVATE
/* add private */
);
// set new run method implementation
final
String
code
=
"{\n"
+
"Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay("
+
capturedFieldName
+
");\n"
+
"try {\n"
+
" return "
+
original_run_method_rename
+
"($$);\n"
+
"} finally {\n"
+
" com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);\n"
+
"}\n"
+
"}"
;
new_runMethod
.
setBody
(
code
);
clazz
.
addMethod
(
new_runMethod
);
logger
.
info
(
"insert code around method "
+
signatureOfMethod
(
runMethod
)
+
" of class "
+
className
+
": "
+
code
);
}
}
src/test/java/com/alibaba/ttl/threadpool/agent/TtlAgentTest.kt
浏览文件 @
76cb5fe8
...
...
@@ -12,11 +12,21 @@ class TtlAgentTest {
assertEquals
(
emptyMap
<
String
,
String
>(),
splitCommaColonStringToKV
(
""
))
assertEquals
(
emptyMap
<
String
,
String
>(),
splitCommaColonStringToKV
(
" "
))
assertEquals
(
mapOf
(
"k1"
to
""
,
"k2"
to
""
),
splitCommaColonStringToKV
(
"k1,k2"
))
assertEquals
(
mapOf
(
"k1"
to
""
,
"k2"
to
""
),
splitCommaColonStringToKV
(
" k1, k2 "
))
assertEquals
(
mapOf
(
"ttl.agent.logger"
to
"STDOUT"
),
splitCommaColonStringToKV
(
"ttl.agent.logger:STDOUT"
))
assertEquals
(
mapOf
(
"k1"
to
"v1"
,
"ttl.agent.logger"
to
"STDOUT"
),
splitCommaColonStringToKV
(
"k1:v1,ttl.agent.logger:STDOUT"
))
assertEquals
(
mapOf
(
"k1"
to
"v1"
,
"ttl.agent.logger"
to
"STDOUT"
),
splitCommaColonStringToKV
(
" k1 :v1 , ttl.agent.logger :STDOUT "
))
assertEquals
(
mapOf
(
"k1"
to
"v1"
,
"ttl.agent.logger"
to
"STDOUT"
,
"k3"
to
""
),
splitCommaColonStringToKV
(
" k1 :v1 , ttl.agent.logger :STDOUT ,k3"
))
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录