如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈( 四 )


如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
代码有点长 , 不必细看 , 主要就是在原方法的BeforeEvent(进入前)和ReturnEvent(执行正常返回后)执行上述的切面逻辑 , 我这里便是使用了一个MAP存储每个Bean的初始化开始和结束时间 , 最终统计出初始化耗时 。
最终 , 我们还需要一个方法来知道我们的原始Spring应用已经启动完毕 , 这样我们可以手动卸载我们的Sandbox模块 , 毕竟他已经完成了他的历史使命 , 不需要再依附在主进程上 。
我们通过一个简陋的办法 , 检查http://127.0.0.1:8080/是否会返回小于500的状态码 , 来判断Spring容器是否已经启动 。当然如果你的Spring没有使用Web框架 , 就不能用这个方法来判断启动完成 , 你也许可以通过Spring自己的生命周期钩子函数来实现 , 这里我是偷了个懒 。
整个SpringBean监听模块的开发就完成了 , 你可以感受到 , 你的开发和日常业务开发几乎没有区别 , 这就是JVM Sandbox带给你的最大好处 。
上述源码放在了我的Github仓库:
https://github.com/monitor4all/javaMonitor
JVM Sandbox底层技术整个JVM Sandbox的入门使用基本上讲完了 , 上文提到了一些JVM技术名词 , 可能小伙伴们听过但不是特别了解 。这里简单阐述几个重要的概念 , 理清楚这几个概念之间的关系 , 以便大家更好的理解JVM Sandbox底层的实现 。
JVMTIJVMTI(JVM Tool Interface)是 Java 虚拟机所提供的 native 编程接口 , JVMTI可以用来开发并监控虚拟机 , 可以查看JVM内部的状态 , 并控制JVM应用程序的执行 。可实现的功能包括但不限于:调试、监控、线程分析、覆盖率分析工具等 。
很多java监控、诊断工具都是基于这种形式来工作的 。如果arthas、jinfo、brace等 , 虽然这些工具底层是JVM TI , 但是它们还使用到了上层工具JavaAgent 。
JavaAgent和InstrumentationJavaagent是java命令的一个参数 。参数 javaagent 可以用于指定一个 jar 包 。
-agentlib:<libname>[=<选项>] 加载本机代理库 <libname>, 例如 -agentlib:hprof 另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help-agentpath:<pathname>[=<选项>] 按完整路径名加载本机代理库-javaagent:<jarpath>[=<选项>] 加载 Java 编程语言代理, 请参阅 java.lang.instrument在上面-javaagent参数中提到了参阅java.lang.instrument , 这是在rt.jar 中定义的一个包 , 该包提供了一些工具帮助开发人员在 Java 程序运行时 , 动态修改系统中的 Class 类型 。其中 , 使用该软件包的一个关键组件就是 Javaagent 。从名字上看 , 似乎是个 Java 代理之类的 , 而实际上 , 他的功能更像是一个Class 类型的转换器 , 他可以在运行时接受重新外部请求 , 对Class类型进行修改 。
Instrumentation的底层实现依赖于JVMTI 。
JVM 会优先加载 带 Instrumentation 签名的方法 , 加载成功忽略第二种 , 如果第一种没有 , 则加载第二种方法 。
Instrumentation支持的接口:
public interface Instrumentation {//添加一个ClassFileTransformer//之后类加载时都会经过这个ClassFileTransformer转换void addTransformer(ClassFileTransformer transformer, boolean canRetransform);void addTransformer(ClassFileTransformer transformer);//移除ClassFileTransformerboolean removeTransformer(ClassFileTransformer transformer);boolean isRetransformClassesSupported();//将一些已经加载过的类重新拿出来经过注册好的ClassFileTransformer转换//retransformation可以修改方法体 , 但是不能变更方法签名、增加和删除方法/类的成员属性void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;boolean isRedefineClassesSupported();//重新定义某个类void redefineClasses(ClassDefinition... definitions)throwsClassNotFoundException, UnmodifiableClassException;boolean isModifiableClass(Class<?> theClass);@SuppressWarnings("rawtypes")Class[] getAllLoadedClasses();@SuppressWarnings("rawtypes")Class[] getInitiatedClasses(ClassLoader loader);long getObjectSize(Object objectToSize);void appendToBootstrapClassLoaderSearch(JarFile jarfile);void appendToSystemClassLoaderSearch(JarFile jarfile);boolean isNativeMethodPrefixSupported();void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);}

经验总结扩展阅读