diff --git a/.travis.yml b/.travis.yml index 1a2df5ca2885ede4d341697929771c6bbcea3ee1..5bbd8762e807e33a9a46a2b82c98c35522992c6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,8 @@ before_install: - echo -e "JAVA_HOME=$JAVA_HOME\nPATH=$PATH\nSHELL=$SHELL" script: - - ./scripts/integration-test.sh + - scripts/integration-test.sh + - ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/integration-test.sh after_success: # codecov diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/README.md b/ttl-integrations/sample-ttl-agent-extension-transformlet/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f4a179d5d5eebe102a08ee576db9edba2b3a50dc --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/README.md @@ -0,0 +1,45 @@ +# `TTL Agent`扩展`Transformlet`实现的示例工程 + +## 扩展`Transformlet`的实现 + +为了提供`TTL Agent`扩展`Transformlet`,包含2部分: + +1. `TTL Agent`扩展`Transformlet`的实现类:[`SampleExtensionTransformlet`](src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java)。 + - 这个示例`Transformlet`修改了类[`ToBeTransformedClass`](src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java)的`toBeTransformedMethod`方法:在修改方法前插入一行代码,修改方法参数值乘以2(`$1 *= 2;`)。 +1. `TTL Agent`扩展`Transformlet`的配置文件:[`META-INF/ttl.agent.transformlets`](src/main/resources/META-INF/ttl.agent.transformlets) + - 配置文件的内容是 扩展`Transformlet`实现类的全类名。 + 在这个示例工程是`com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet`。 + - `TTL Agent`会扫描`Class Path`上的`META-INF/ttl.agent.transformlets`文件,自动发现并启用这些扩展`Transformlet`。 + 即只要将扩展`Transformlet`的依赖`Jar`引入到应用中就会自动生效。 + - 这个扫描并自动加载生效与`JDK`的[`ServiceLoader`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html)一样,只是使用不同的扩展配置文件。 + +## 扩展`Transformlet`的测试与生效验证 + +单元测试类 在 [`ToBeTransformedClassTest`](src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java)。 + +通过运行`Maven`单元测试验证扩展`Transformlet` `SampleExtensionTransformlet`是否生效: + + +```bash +# sample-ttl-agent-extension-transformlet 工程目录,执行 + +# 1. 先 mvn install TTL lib +(cd ../.. && mvn install -Dmaven.test.skip) + +# 2. 验证 扩展Transformlet SampleExtensionTransformlet 是否生效 +mvn test -Penable-TtlAgent-forTest +# 更多输出TTL的Transform类操作的日志 +mvn test -Penable-TtlAgent-forTest -Penable-LogTransform-forTest +``` + +## 运行示例`SampleMain` + +可以通过`Java`命令行参数来运行示例`SampleMain`: + +```java +java -javaagent:path/to/transmittable-thread-local-2.x.y.jar \ + -cp target/classes \ + com.alibaba.ttl.agent.extension_transformlet.sample.biz.SampleMain +``` + +通过脚本[`scripts/run.sh`](scripts/run.sh)快速上面命令行的运行。 diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/pom.xml b/ttl-integrations/sample-ttl-agent-extension-transformlet/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f81bfa7eb3fd954b6001fb9ac1744c4fb83679a0 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/pom.xml @@ -0,0 +1,109 @@ + + 4.0.0 + + com.alibaba + sample-ttl-agent-extension-transformlet + 1.0.0-SNAPSHOT + jar + ${project.artifactId} + + + 1.8 + 1.8 + UTF-8 + + 2.13.0-SNAPSHOT + + + + + com.alibaba + transmittable-thread-local + ${ttl.version} + + + junit + junit + 4.13.1 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + + + + enable-TtlAgent-forTest + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + ${surefire.verbose.class} + -javaagent:${com.alibaba:transmittable-thread-local:jar}=ttl.agent.logger:STDOUT + ${surefire.ttl.agent.log.class.transform} + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.2 + + + initialize + + properties + + + + + + + + + enable-LogTransform-forTest + + -Dttl.agent.log.class.transform + + + + enable-verboseClass-forTest + + -verbose:class + + + + diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/integration-test.sh b/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/integration-test.sh new file mode 100755 index 0000000000000000000000000000000000000000..b17cb32be7f488cae6a61cefeb8443f848205de5 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/integration-test.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -eEuo pipefail +# adjust current dir to project dir +cd "$(dirname "$(readlink -f "$0")")/.." + +TTL_ROOT_PROJECT_DIR="$(dirname "$(readlink -f "../")")" + +source "$TTL_ROOT_PROJECT_DIR/scripts/common_build.sh" +source "$TTL_ROOT_PROJECT_DIR/scripts/prepare-jdk.sh" + +for jv in 8 11; do + switch_to_jdk "$jv" + + headInfo "test with JDK $JAVA_HOME" + + MVN_WITH_BASIC_OPTIONS test + MVN_WITH_BASIC_OPTIONS test -Penable-TtlAgent-forTest +done diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/run.sh b/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..6e35a5e80f4a9bde5c3321d4effa2847a1a80ba6 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/run.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -eEuo pipefail +# adjust current dir to project dir +cd "$(dirname "$(readlink -f "$0")")/.." + +TTL_ROOT_PROJECT_DIR="$(dirname "$(readlink -f "../")")" + +source "$TTL_ROOT_PROJECT_DIR/scripts/common_build.sh" + +ttl_version=$(extractFirstElementValueFromPom version "../../pom.xml") + +readonly ttl_agent_path="$TTL_ROOT_PROJECT_DIR/target/transmittable-thread-local-$ttl_version.jar" + +mvn_ttl_lib() { + ( + cd "$TTL_ROOT_PROJECT_DIR" + MVN_WITH_BASIC_OPTIONS -q -Dmaven.test.skip "$@" + ) +} + +if [ "${1:-}" != "skipClean" ]; then + mvn_ttl_lib clean package + + # compile sample-ttl-agent-extension-transformlet + MVN_WITH_BASIC_OPTIONS -q clean compile +else + if [ ! -f "$ttl_agent_path" ]; then + mvn_ttl_lib package + fi + + # compile sample-ttl-agent-extension-transformlet + MVN_WITH_BASIC_OPTIONS -q compile +fi + +readonly ttl_agent_options="-javaagent:$ttl_agent_path=ttl.agent.logger:STDOUT,ttl.agent.log.class.transform:true" + +readonly main_class=com.alibaba.ttl.agent.extension_transformlet.sample.biz.SampleMain + +logAndRun "$JAVA_HOME/bin/java" -Duser.language=en -Duser.country=US \ + "${ttl_agent_options}" \ + -cp target/classes $main_class diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/SampleMain.java b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/SampleMain.java new file mode 100644 index 0000000000000000000000000000000000000000..3010f490798a5ba9e991b63496252be82aba1272 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/SampleMain.java @@ -0,0 +1,23 @@ +package com.alibaba.ttl.agent.extension_transformlet.sample.biz; + +import com.alibaba.ttl.threadpool.agent.TtlAgent; +import com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo; + +public class SampleMain { + /** + * @see ToBeTransformedClass#toBeTransformedMethod(int) + * @see com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet#doTransform(ClassInfo) + */ + public static void main(String[] args) throws Exception { + final ToBeTransformedClass instance = new ToBeTransformedClass(); + + System.out.println("========================================"); + if (TtlAgent.isTtlAgentLoaded()) { + System.out.println("Run WITH TTL Agent"); + } else { + System.out.println("Run Without TTL Agent"); + } + System.out.println(instance.toBeTransformedMethod(21)); + System.out.println("========================================"); + } +} diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java new file mode 100644 index 0000000000000000000000000000000000000000..bdb206dbfe10cf97193e069fa6b6deb1c8daec09 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java @@ -0,0 +1,7 @@ +package com.alibaba.ttl.agent.extension_transformlet.sample.biz; + +public class ToBeTransformedClass { + public int toBeTransformedMethod(int input) { + return input; + } +} diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java new file mode 100644 index 0000000000000000000000000000000000000000..e64d6d26919279ecc9b88f026d6b9f82e4679957 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java @@ -0,0 +1,43 @@ +package com.alibaba.ttl.agent.extension_transformlet.sample.transformlet; + +import com.alibaba.ttl.agent.extension_transformlet.sample.biz.ToBeTransformedClass; +import com.alibaba.ttl.threadpool.agent.logging.Logger; +import com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo; +import com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet; +import com.alibaba.ttl.threadpool.agent.transformlet.javassist.CannotCompileException; +import com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtClass; +import com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtMethod; +import com.alibaba.ttl.threadpool.agent.transformlet.javassist.NotFoundException; + +import java.io.IOException; + +/** + * {@link TtlTransformlet} for {@link ToBeTransformedClass}. + * + * Caution:
+ * MUST use string constant for class/method name! + *

+ * MUST NOT use {@code Class class = ToBeTransformedClass.class} to get the class to be transformed({@code ToBeTransformedClass}), + * {@code ToBeTransformedClass.class} operation will force to load the class to be transformed, + * and cause the Transformlet to SKIP the class transform! + */ +public class SampleExtensionTransformlet implements TtlTransformlet { + private static final Logger logger = Logger.getLogger(SampleExtensionTransformlet.class); + + public static final String TO_BE_TRANSFORMED_CLASS_NAME = "com.alibaba.ttl.agent.extension_transformlet.sample.biz.ToBeTransformedClass"; + public static final String TO_BE_TRANSFORMED_METHOD = "toBeTransformedMethod"; + + public void doTransform(ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException { + if (!classInfo.getClassName().equals(TO_BE_TRANSFORMED_CLASS_NAME)) return; + + final CtClass ctClass = classInfo.getCtClass(); + final CtMethod method = ctClass.getDeclaredMethod(TO_BE_TRANSFORMED_METHOD); + + final String code = "$1 *= 2;"; + method.insertBefore(code); + logger.info("[SampleExtensionTransformlet] insert code before method " + TO_BE_TRANSFORMED_METHOD + + " of class " + method.getDeclaringClass().getName() + ": " + code); + + classInfo.setModified(); + } +} diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/resources/META-INF/ttl.agent.transformlets b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/resources/META-INF/ttl.agent.transformlets new file mode 100644 index 0000000000000000000000000000000000000000..e93147c53deddb7760365d49d9c4da7e2169ef1d --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/resources/META-INF/ttl.agent.transformlets @@ -0,0 +1 @@ +com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet diff --git a/ttl-integrations/sample-ttl-agent-extension-transformlet/src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java new file mode 100644 index 0000000000000000000000000000000000000000..16143cf80d5db42350204184ef61c05364278c64 --- /dev/null +++ b/ttl-integrations/sample-ttl-agent-extension-transformlet/src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java @@ -0,0 +1,25 @@ +package com.alibaba.ttl.agent.extension_transformlet.sample.biz; + +import com.alibaba.ttl.threadpool.agent.TtlAgent; +import org.junit.Test; + +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +public class ToBeTransformedClassTest { + @Test + public void test_method1() { + final ToBeTransformedClass instance = new ToBeTransformedClass(); + + System.out.println("========================================"); + if (TtlAgent.isTtlAgentLoaded()) { + System.out.println("Test **WITH** TTL Agent"); + assertEquals(42, instance.toBeTransformedMethod(21)); + } else { + System.out.println("Test WITHOUT TTL Agent"); + assertEquals(21, instance.toBeTransformedMethod(21)); + } + System.out.println("========================================"); + } +}