动态 Java
Java 动态性,正在不断补充。如果用 JS 这些动态语言那当然简单。
选型 | Java 动态代理 | JavaAgent/Instrument/动态编译 | ASM | cglib | Javassist |
---|---|---|---|---|---|
是否 Java 自带 | yes | yes | no | no | no |
使用场景 | 监控和控制虚拟机的行为 | 字节码生成框架 | 字节码生成框架,基于 ASM | ||
优点 | 自带 | 快速 | 快速简单 | 快速简单 | |
缺点 | 对 main方法或jar 实施 | 需要接口,语法晦涩 | 过于底层,需要字节码知识 | ||
官网 | n/a | n/a | https://asm.ow2.io/ | https://github.com/cglib/cglib | http://www.javassist.org/ |
Ref:
- Java APT
- JavaPoet (https://github.com/square/javapoet)生成 Java 文件而不是字节码
- https://blog.csdn.net/u010072711/article/details/77040159
- https://www.jianshu.com/p/5514cf705666
- https://blog.csdn.net/zhuoxiuwu/article/details/78619645
- https://blog.csdn.net/qq_32115439/article/details/78361596
- 组件化 https://www.jianshu.com/p/0d45f2a894ba
- MethodHandle,类似于反射中的Method类,但它比Method类要更加灵活和轻量级 https://blog.csdn.net/sunjiaminaini/article/details/76976694 https://cloud.tencent.com/developer/article/1005920
热加载
选型:
- JRebel 收费,要破解,麻烦
- Spring-loaded,不太清楚,是否依赖 Spring?
- 使用 jdb,自带的命令行调试工具,不太清楚
- 使用 idea,不太清楚,我用 Eclipse 的,是否自带不需要插件?
- OSGi + Gradle osgi-run plugin + Apache Felix,老外介绍的,貌似比较麻烦,不清楚
- 基于 Jetty 的热加载,Tomcat 不行,可参考 JFinal 实现,另外 Act 也实现了热加载
- DCEVM+ HotSwapAgent 开源,不知道坑怎么样,打算试试
两篇介绍热加载不错 的文章
IOC 注解
Spring | JSR330 | Ajaxjs |
---|---|---|
@Component | @Named | @Resources |
@Autowired | @Inject | @Bean |
@Qualifier | @Named | @Resources |
基于包的模块
一个包是一个代码集合,对外暴露的只是在这个包里面的一个接口和实现,其他不可见
Javassist
添加一个 setter
ClassPool pool = ClassPool.getDefault();
CtClass cc;
try {
cc = pool.get("com.ajaxjs.ioc.Hi");
// CtMethod m = CtNewMethod.make("public void setPerson(com.ajaxjs.ioc.Person person) { this.person = person; }", cc);
// cc.addMethod(m);
// 或者
CtField f1 = new CtField(pool.get("com.ajaxjs.ioc.Person"), "person", cc);
cc.addMethod(CtNewMethod.setter("setPerson", f1));
// Class<?> c = cc.toClass(this.getClass().getClassLoader());
cc.toClass();
} catch (NotFoundException | CannotCompileException e) {
e.printStackTrace();
}
修改的前提即是当前修改的类还没有被当前 jvm 加载,如果当前的类已经被加载,则不能修改。需要注意的是,在调用 ctClass.toClass() 时,会加载此类,如果此类在之前已经被加载过,则会报一个 duplicate load 的错误,表示不能重复加载一个类。所以,修改方法的实现必须在修改的类加载之前进行。即使不调用 toClass,那么如果当前修改的类已经加载,那么修改方法实现,同样不起作用,即修改一个已经加载的类(不论是修改静态方法,还是修改动态方法)是没有任何效果的。修改之前必须在类加载之前进行。
怎么动态重载Class?
如果 JVM 运行时开启 JPDA(Java Platform Debugger Architecture),则 Class 是运行被动态重新载入的。具体方式可以参考 java.lang.Instrument。javassist也提供了一个运行期重载 Class 的方法,具体可以看API 中的javassist.tools.HotSwapper。参考:http://www.cnblogs.com/zhjh256/p/6286198.html
获取方法名称
Java 8 的反射也可以,但是要打开编译开关,比较麻烦的说。Javassist 则不存在这个问题,对于任意方法,都能正确的获取其参数的参数名。参见 LocalVariableAttribute。
- https://blog.csdn.net/21aspnet/article/details/81671777
- https://www.cnblogs.com/sunfie/p/5154246.html
- https://www.cnblogs.com/hucn/p/3636912.html
动态添加、修改 Java 注解
怎么动态添加、修改 Java 注解?有人说用动态代理,其实不必,因为动态代理需要实现代理的接口,比较不方便;有人说用 Javassist,那是方便,不过也要加 jar 包;其实最省事的就是 java 反射。
参考:
- https://rationaleemotions.wordpress.com/2016/05/27/changing-annotation-values-at-runtime/
- https://gist.github.com/games647/4650fde607b02215a1a4f95bca98e7ea
- https://gist.github.com/henrrich/185503f10cbb2499a0dc75ec4c29c8f2