- 浏览: 262017 次
- 性别:
- 来自: 多伦多
文章分类
- 全部博客 (127)
- Java 基础 (46)
- Java EE (3)
- Clouds (1)
- Spring 编程 (7)
- Spring Batch 编程 (1)
- Quartz 编程 (9)
- Seam 编程 (4)
- Hibernate 编程 (1)
- JSF 编程 (3)
- jQuery 编程 (3)
- Interview Question 汇总 (3)
- 日常应用 (3)
- Maven 编程 (2)
- WebService 编程 (10)
- Scala 编程 (5)
- Coherence 编程 (8)
- OO 编程 (1)
- Java 线程 (6)
- DB 编程 (2)
- WebService 安全 (4)
- Oracle Fusion 编程 (2)
- JavsScript/Ajax 编程 (1)
最新评论
-
chainal:
赞,说的很好
Scala 有趣的Trait -
wuliupo:
RRRR-MM-DD HH24:MI:SS
如何让Oracle SQL Developer显示的包含在日期字段中的时间 -
pengain:
...
使用Spring Roo ,感受ROR式的开发 -
zeng1990:
def getPersonInfo() = {
(&quo ...
Java 的继位人? - Scala简介 -
zeng1990:
我使用的是2.9.2版本的!
Java 的继位人? - Scala简介
(转自http://baike.baidu.com/view/1589420.html)
Java SE 6新特性:Instrumentation,利用 Java 代码,即 java.lang.instrument 做动态 Instrumentation 是 Java SE 5 的新特性,它把 Java 的 instrument 功能从本地代码中解放出来,使之可以用 Java 代码的方式解决问题。使用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java 类操作了,这样的特性实际上提供了一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP 的功能了。
在 Java SE 6 里面,instrumentation 包被赋予了更强大的功能:启动后的 instrument、本地代码(native code)instrument,以及动态改变 classpath 等等。这些改变,意味着 Java 具有了更强的动态控制、解释能力,它使得 Java 语言变得更加灵活多变。
在 Java SE6 里面,最大的改变使运行时的 Instrumentation 成为可能。在 Java SE 5 中,Instrument 要求在运行前利用命令行参数或者系统参数来设置代理类,在实际的运行之中,虚拟机在初始化之时(在绝大多数的 Java 类库被载入之前),instrumentation 的设置已经启动,并在虚拟机中设置了回调函数,检测特定类的加载情况,并完成实际工作。但是在实际的很多的情况下,我们没有办法在虚拟机启动之时就为其设定代理,这样实际上限制了 instrument 的应用。而 Java SE 6 的新特性改变了这种情况,通过 Java Tool API 中的 attach 方式,我们可以很方便地在运行过程中动态地设置加载代理类,以达到 instrumentation 的目的。
另外,对 native 的 Instrumentation 也是 Java SE 6 的一个崭新的功能,这使以前无法完成的功能 —— 对 native 接口的 instrumentation 可以在 Java SE 6 中,通过一个或者一系列的 prefix 添加而得以完成。
最后,Java SE 6 里的 Instrumentation 也增加了动态添加 class path 的功能。所有这些新的功能,都使得 instrument 包的功能更加丰富,从而使 Java 语言本身更加强大。
Instrumentation 的基本功能和用法
“java.lang.instrument”包的具体实现,依赖于 JVMTI。JVMTI(Java Virtual Machine Tool Interface)是一套由 Java 虚拟机提供的,为 JVM 相关的工具提供的本地编程接口集合。JVMTI 是从 Java SE 5 开始引入,整合和取代了以前使用的 Java Virtual Machine Profiler Interface (JVMPI) 和 the Java Virtual Machine Debug Interface (JVMDI),而在 Java SE 6 中,JVMPI 和 JVMDI 已经消失了。JVMTI 提供了一套”代理”程序机制,可以支持第三方工具程序以代理的方式连接和访问 JVM,并利用 JVMTI 提供的丰富的编程接口,完成很多跟 JVM 相关的功能。事实上,java.lang.instrument 包的实现,也就是基于这种机制的:在 Instrumentation 的实现当中,存在一个 JVMTI 的代理程序,通过调用 JVMTI 当中 Java 类相关的函数来完成 Java 类的动态操作。除开 Instrumentation 功能外,JVMTI 还在虚拟机内存管理,线程控制,方法和变量操作等等方面提供了大量有价值的函数。
Instrumentation 的最大作用,就是类定义动态改变和操作。在 Java SE 5 及其后续版本当中,开发者可以在一个普通 Java 程序(带有 main 函数的 Java 类)运行时,通过 –javaagent 参数指定一个特定的 jar 文件(包含 Instrumentation 代理)来启动 Instrumentation 的代理程序。
在 Java SE 5 当中,开发者可以让 Instrumentation 代理在 main 函数运行前执行。简要说来就是如下几个步骤:
编写 premain 函数
编写一个 Java 类,包含如下两个方法当中的任何一个
public static void premain(String agentArgs, Instrumentation inst); [1]
public static void premain(String agentArgs); [2]
其中,[1] 的优先级比 [2] 高,将会被优先执行([1] 和 [2] 同时存在时,[2] 被忽略)。
在这个 premain 函数中,开发者可以进行对类的各种操作。
agentArgs 是 premain 函数得到的程序参数,随同 “–javaagent”一起传入。与 main 函数不同的是,这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。
Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
jar 文件打包
将这个 Java 类打包成一个 jar 文件,并在其中的 manifest 属性当中加入” Premain-Class”来指定步骤 1 当中编写的那个带有 premain 的 Java类。(可能还需要指定其他属性以开启更多功能)
运行
用如下方式运行带有 Instrumentation 的 Java 程序:
java -javaagent:jar文件的位置[=传入premain的参数]
对 Java 类文件的操作,可以理解为对一个 byte 数组的操作(将类文件的二进制字节流读入一个 byte 数组)。开发者可以在“ClassFileTransformer”的 transform 方法当中得到,操作并最终返回一个类的定义(一个 byte 数组)。这方面,Apache 的 BCEL 开源项目提供了强有力的支持,读者可以在参考文章“Java SE 5 特性 Instrumentation 实践”中看到一个 BCEL 和 Instrumentation 结合的例子。具体的字节码操作并非本文的重点,所以,本文中所举的例子,只是采用简单的类文件替换的方式来演示 Instrumentation 的使用。
下面,我们通过简单的举例,来说明 Instrumentation 的基本使用方法。
首先,我们有一个简单的类,TransClass, 可以通过一个静态方法返回一个整数 1。
public class TransClass {
public int getNumber() {
return 1;
}
}
我们运行如下类,可以得到输出 ”1“。
public class TestMainInJar {
public static void main(String[] args) {
System.out.println(new TransClass().getNumber());
}
}
然后,我们将 TransClass 的 getNumber 方法改成如下:
public int getNumber() {
return 2;
}
再将这个返回 2 的 Java 文件编译成类文件,为了区别开原有的返回 1 的类,我们将返回 2 的这个类文件命名为 TransClass2.class.2。
接下来,我们建立一个 Transformer 类:
Java 代码:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; class Transformer implements ClassFileTransformer { public static final String classNumberReturns2 = "TransClass.class.2"; public static byte[] getBytesFromFile(String fileName) { try { // precondition File file = new File(fileName); InputStream is = new FileInputStream(file); long length = file.length(); byte[] bytes = new byte[(int) length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset <bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; } if (offset < bytes.length) { throw new IOException("Could not completely read file "+ file.getName()); } is.close(); return bytes; } catch (Exception e) { System.out.println("error occurs in _ClassTransformer!"+ e.getClass().getName()); return null; } } public byte[] transform(ClassLoader l, String className, Class<?> c, ProtectionDomain pd, byte[] b) throws IllegalClassFormatException { if (!className.equals("TransClass")) { return null; } return getBytesFromFile(classNumberReturns2); } }
这个类实现了 ClassFileTransformer 接口。其中,getBytesFromFile 方法根据文件名读入二进制字符流,而 ClassFileTransformer 当中规定的 transform 方法则完成了类定义的替换转换。
最后,我们建立一个 Premain 类,写入 Instrumentation 的代理方法 premain:
Java 代码:
public class Premain { public static void premain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException { inst.addTransformer(new Transformer()); } }
可以看出,addTransformer 方法并没有指明要转换哪个类。转换发生在 premain 函数执行之后,main 函数执行之前,这时每装载一个类,transform 方法就会执行一次,看看是否需要转换,所以,在 transform(Transformer 类中)方法中,程序用 className.equals("TransClass") 来判断当前的类是否需要转换。
代码完成后,我们将他们打包为 TestInstrument1.jar。返回 1 的那个 TransClass 的类文件保留在 jar 包中,而返回 2 的那个 TransClass.class.2 则放到 jar 的外面。在 manifest 里面加入如下属性来指定 premain 所在的类:
Manifest-Version: 1.0
Premain-Class: Premain
在运行这个程序的时候,如果我们用普通方式运行这个 jar 中的???椠?? main 函数,可以得到输出“1”。如果用下列方式运行:
java –javaagent:TestInstrument1.jar –cp TestInstrument1.jar TestMainInJar
则会得到输出“2”。
当然,程序运行的 main 函数不一定要放在 premain 所在的这个 jar 文件里面,这里只是为了例子程序打包的方便而放在一起的。
除开用 addTransformer 的方式,Instrumentation 当中还有另外一个方法“redefineClasses”来实现 premain 当中指定的转换。用法类似,如下:
Java 代码:
public class Premain { public static void premain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException { ClassDefinition def = new ClassDefinition(TransClass.class, Transformer .getBytesFromFile(Transformer.classNumberReturns2)); inst.redefineClasses(new ClassDefinition[] ); System.out.println("success"); } }
redefineClasses 的功能比较强大,可以批量转换很多类。
发表评论
-
设计模式之事务处理
2010-11-25 07:36 914转自 http://www.blogjava.net/kill ... -
设计自己的MVC框架(1)
2010-11-25 07:27 1253转自 http://www.blogjava.net/ ... -
设计自己的MVC框架(2)
2010-11-25 07:24 1178转自 http://www.blogjava.ne ... -
使用Annotation设计持久层
2010-11-25 06:59 956(From http://www.blogjava. ... -
Jakarta Commons StringUtils类使用
2010-11-25 06:58 935转自http://www.blogjava.net/ ... -
Jakarta Commons ArrayUtils类使用
2010-11-25 06:57 1133转自http://www.blogjava.net/ ... -
Reflection的三个动态性质
2010-11-25 06:56 1013转自http://www.blogjava. ... -
用commons.fileupload实现文件的上传和下载
2010-11-25 06:55 1401转自http://www.blogjav ... -
JAVA基础:共享内存在Java中的实现和应用
2010-11-25 06:54 874(转自 http://www.bu ... -
JAVA变量类型之间的相互转换
2010-11-25 06:52 899(转自 http://www.builder.c ... -
优秀Java程序员必须了解的GC工作原理
2010-11-25 06:52 889(转自 http://www.build ... -
几种版权信息详解
2010-11-25 06:49 1132BSD开源协议(original ... -
Java JDK 1.4 JCE Provider issue.
2010-11-25 06:48 1175Bundled JCE provider in jdk1 ... -
Why use Map.entrySet() instead of Map.keySet()?
2010-11-25 06:45 1394(From http://www.coderan ... -
Credit Card Mod10 校验
2010-11-25 06:27 2077以下是几种Mod10的实现。第一种最为简洁,最后一种 ... -
如何知道方法的调用者
2010-11-25 05:57 7399转自http://hellboys.bok ... -
Java加解密的基础
2010-11-25 05:49 2822在Java的安全包中,包括了三部分内容: ... -
Java日志框架:SLF4J, Apache Common-Logging, Log4J和Logback
2010-11-25 05:47 1859Log4j Apache的一个开放源代码项目,通过 ... -
JBOSS 启动 加载 过程
2010-09-11 00:26 3026(转自: http://blog.csdn.net/ylli_ ... -
JAVA性能优化—Sun Hotspot JDK JVM参数设置
2010-09-11 00:18 1208(转自: http://www.hashei.me/2009/ ...
相关推荐
Java SE 6,代号 Mustang,是Java发展过程中的一个重要版本,它在性能上有所提升,并引入了一系列新特性,尤其是在API库方面。其中,Instrumentation是Java SE 6的一个亮点,它允许开发者创建独立于应用程序的代理...
5. **Instrumentation新功能**:JDK1.6扩展了Java代理(Java Agents)和Instrumentation API,允许开发者在运行时修改类文件,实现了对程序行为的深度监控和分析,这对于性能调试和代码优化非常有用。 6. **Java DB...
利用 Java 代码,即 java.lang.instrument 做动态 Instrumentation 是 Java SE 5 的新特性,它把 Java 的 instrument 功能从本地代码中解放出来,使之可以用 Java 代码的方式解决问题。使用 Instrumentation,开发者...
- **动态类路径添加**:在 Java 6 中,通过 `Instrumentation.appendToSystemClassLoaderSearch()` 方法,可以在运行时动态地添加新的类路径资源。 #### 八、总结 Java Instrumentation 提供了一种强大的机制,使...
在Java SE 6中,`java.lang.instrument`包被赋予了更强大的功能,包括启动后的Instrument、本地代码(native code)Instrument以及动态改变classpath等特性。这些变化进一步提升了Java语言的灵活性和动态性。 #####...
在Java SE 5以后的版本中引入的Instrumentation接口允许开发者在不重新启动JVM的情况下动态地修改已经加载的类的行为。通过Instrumentation提供的接口,可以实现对类定义的修改,并通过添加agent的方式来改变应用的...
#### 一、Java SE **1.1 深入 Java API** **1.1.1 Lang包** - **String类与 StringBuffer类** - `String` 类不可变,一旦创建后其内容无法更改;而 `StringBuffer` 类则允许在原有基础上修改字符串。`...
- **适用范围**: 这个版本支持多种环境,包括但不限于 Java SE 6、Java SE 7 和 Java SE 8,同时也兼容 Java EE 6 和 Java EE 7 规范。 ##### 2. **核心概念与架构** - **依赖注入 (DI) 与控制反转 (IoC)**: ...
Java SE(J2SE)是Java平台标准版的简称,它是Java开发环境的基础,提供了丰富的类库和API供开发者使用。以下是对标题和描述中涉及的一些知识点的详细解释: 1. **Desktop类**:`java.awt.Desktop`类允许用户通过...
Java∨ ersion se6 支持脚本语言 引入JDBC40API; 引入 Java Compiler API; 可插拔注解; 增加对 Native PKi( Public Key Infrastructure)、 Java gss( Generic Security Service) Kerberos和 LDAP(Lightweight ...
Spring框架是一个开源的轻量级Java SE/EE全栈解决方案,提供了对依赖注入、面向切面编程的支持,使得Java EE应用程序开发变得更加简单,功能更加强大。 - **核心容器**:包括Spring Core、Spring Beans、Spring ...
随着版本的更新,Spring引入了新特性和改进,例如对注解的更好支持、对异步处理的改进、对RESTful Web服务的支持等。 2、什么是SpringFramework? Spring是一个开源的Java/Java EE全功能栈应用程序框架,旨在简化...
Spring 是一个用于构建 Java SE/EE 应用的分层的、全栈式的轻量级开源框架,它以 IOC(控制反转)和 AOP(面向切面编程)作为其核心设计理念。Spring 提供了丰富的功能模块,包括展现层的 Spring MVC 和持久层的 ...
Spring框架广泛应用于各种类型的企业级应用开发,无论是在传统的Java SE环境还是Java EE环境中,Spring都能发挥重要作用。具体应用场景包括但不限于: - **Web应用开发**:利用Spring MVC框架快速构建RESTful服务。...