Skip to content

Latest commit

 

History

History
109 lines (74 loc) · 4.63 KB

developer-guide.md

File metadata and controls

109 lines (74 loc) · 4.63 KB

🎓 Developer Guide

Java Agent方式对应用代码无侵入

相对修饰Runnable或是线程池的方式,Java Agent方式为什么是应用代码无侵入的?

构架图

按框架图,把前面示例代码操作可以分成下面几部分:

  1. 读取信息设置到TTL
    这部分在容器中完成,无需应用参与。
  2. 提交Runnable到线程池。要有修饰操作Runnable(无论是直接修饰Runnable还是修饰线程池)。
    这部分操作一定是在用户应用中触发。
  3. 读取TTL,做业务检查。
    SDK中完成,无需应用参与。

只有第2部分的操作和应用代码相关。

如果不通过Java Agent修饰线程池,则修饰操作需要应用代码来完成。

使用Java Agent方式,应用无需修改代码,即做到 相对应用代码 透明地完成跨线程池的上下文传递。

如何权衡Java Agent方式的失效情况

把这些失效情况都解决了是最好的,但复杂化了实现。下面是一些权衡:

  • 不推荐使用Timer类,推荐用ScheduledThreadPoolExecutorScheduledThreadPoolExecutor实现更强壮,并且功能更丰富。 如支持配置线程池的大小(Timer只有一个线程);TimerRunnable中抛出异常会中止定时执行。
  • 覆盖了executesubmitschedule的问题的权衡是: 业务上没有修改这些方法的需求。并且线程池类提供了beforeExecute方法用于插入扩展的逻辑。

已有Java Agent中嵌入TTL Agent

这样可以减少Java命令上Agent的配置。

在自己的ClassFileTransformer中调用TtlTransformer,示例代码如下:

public class TransformerAdaptor implements ClassFileTransformer {
    final TtlTransformer ttlTransformer = new TtlTransformer();

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer)
            throws IllegalClassFormatException {
        final byte[] transform = ttlTransformer.transform(
            loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
        if (transform != null) {
            return transform;
        }

        // Your transform code ...

        return null;
    }
}

注意还是要在bootclasspath上,加上TTL依赖的2个Jar:

-Xbootclasspath/a:/path/to/transmittable-thread-local-2.0.0.jar:/path/to/your/agent/jar/files

Bootstrap上添加通用库的Jar的问题及解决方法

通过Java命令参数-Xbootclasspath把库的JarBootstrap ClassPath上。Bootstrap ClassPath上的Jar中类会优先于应用ClassPathJar被加载,并且不能被覆盖。

TTLBootstrap ClassPath上添加了Javassist的依赖,如果应用中如果使用了Javassist,实际上会优先使用Bootstrap ClassPath上的Javassist,即应用不能选择Javassist的版本,应用需要的JavassistMTCJavassist有兼容性的风险。

可以通过repackage(重新命名包名)来解决这个问题。

Maven提供了Shade插件,可以完成repackage操作,并把Javassist的类加到TTLJar中。

这样就不需要依赖外部的Javassist依赖,也规避了依赖冲突的问题。

📚 相关资料

Jdk core classes

Java Agent

Javassist

Shade插件