想必不少人听说过javaagent,但是很少人听说Instrumentation,其实Instrumentation就是javaagent的实现机制,说到Instrumentation,就必须想了解java的attach机制,那就先说下attach的实现。
大家进行jstack的时候,是不是经常看到两个线程Signal Dispatcher和 Attach Listener线程,可能不知道是干嘛的吧,这两个线程是实现attach的关键所在,其中前者是在jvm启动的时候就会创建的,后者只有接收过attach请求的时候vm才会创建,顾名思义,Signal Dispatcher是分发信号的, Attach Listener 是处理attach请求的,那么两者有什么关系呢,当我们执行attach方法的时候,会向目标vm发出一个SIGQUIT 的信号,目标vm收到这个信号之后就会创建Attach Listener线程了,当然jvm保证了不会多创建。
1 path = findSocketFile(pid);
2 if (path == null) {
3 File f = new File(tmpdir, ".attach_pid" + pid);
4 createAttachFile(f.getPath());
5 try {
6 sendQuitTo(pid);
7
8 // give the target VM time to start the attach mechanism
9 int i = 0;
10 long delay = 200;
11 int retries = (int)(attachTimeout() / delay);
12 do {
13 try {
14 Thread.sleep(delay);
15 } catch (InterruptedException x) { }
16 path = findSocketFile(pid);
17 i++;
18 } while (i <= retries && path == null);
19 if (path == null) {
20 throw new AttachNotSupportedException(
21 "Unable to open socket file: target process not responding " +
22 "or HotSpot VM not loaded");
23 }
24 } finally {
25 f.delete();
26 }
27 }
Attach机制说得简单点就是提供A进程可以连上B进程(当然是java进程),创建socket进行通信,A通过发命令给B,B然后对命令进行截取从自己的vm中获取信息发回给客户端vm,但是并不是随便发指令都会处理的,那么attach Listener接收哪些命令呢,如下所示
static AttachOperationFunctionInfo funcs[] = {
{ "agentProperties", get_agent_properties },
{ "datadump", data_dump },
{ "dumpheap", dump_heap },
{ "load", JvmtiExport::load_agent_library },
{ "properties", get_system_properties },
{ "threaddump", thread_dump },
{ "inspectheap", heap_inspection },
{ "setflag", set_flag },
{ "printflag", print_flag },
{ "jcmd", jcmd },
{ NULL, NULL }
};
Instrumentation的实现其实主要使用了load这个指令,它用来实现让target vm动态加载agentlib,Instrumentation的实现在一个名为libinstrument.dylib的动态lib库,linux下是libinstrument.so,它是基于jvmti接口实现的,因此在对其进行load的时候会创建一个agent实例,并往jvmti环境注册一些回调方法,比如监听类文件加载的事件,vm初始化完成事件等,执行Agent_OnAttach,这里会创建一个Instrumentation实例并返回给用户供大家扩展Instrumentation,比如增加一些transform。并会执行Instrumentation实例的loadClassAndCallAgentmain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的agentmain方法,当vm初始化完毕之后,会调用loadClassAndCallPremain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的pre main方法。在类进行加载的时候会调用Instrumentation的transform方法,可以看看参数里有个byte数组,这个数组其实就是正在加载的class字节码,所以如果要字节码增强在这里就可以入手啦,甚至可以实现偷天换日.
posted @
2013-04-12 22:38 你假笨 阅读(2193) |
评论 (0) |
编辑 收藏
最近在忙一个项目,使用的是Flex+Spring+Hibernate,期间碰到一个问题,有必要在此记录一下,也方便有相似问题的来者参考下
问题描述:有一个用户表和一个用户详情表,这两个表是一个一对一的单向关联关系,即在用户表中一个外键引用用户详情表,我在UserInfo的映射文件中使用的是many-to-one,设置了unique="true"表示一对一关系,设置了cascade="save-update"表示的是在保存useInfo对象的时候会自动保存与之关联的userDetails临时对象,即我希望的是先执行一个在用户详情表中的插入语句然后再执行一个在用户表中的插入语句,userInfo对象是从flex端传过来的,当然也设置了userDetails属性的值,在userInfo的dao文件中save方法是这样的
public IvUserInfo save(IvUserInfo transientInstance) {
log.debug("saving IvUserInfo instance");
try {
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
return transientInstance;
}
后面发现执行的sql语句只有一条插入语句,就是在用户表中的一个插入,由于外键的关联作用,是用户表的这条插入也无法执行,这就是问题所在了。
问题解决:这个问题我也没有具体研究Hibernate的源码,我先写了个测试类,发现仅仅在java中执行操作的话是可以正确执行两条插入语句的,但是通过flex传过来就有问题了,那说明是flex端传参数过来的问题,于是我试着修改UserInfo的save方法:
public IvUserInfo save(IvUserInfo transientInstance) {
log.debug("saving IvUserInfo instance");
try {
IvUserDetails ud=new IvUserDetails();
ud.setQq(transientInstance.getIvUserDetails().getQq());
transientInstance.setIvUserDetails(ud);
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
return transientInstance;
}
这样一来问题解决了,顺利执行了两条插入语句。
如果朋友知道具体原因的话希望给我留言了,同时也希望该记录能帮助碰到此类问题的朋友。
posted @
2010-06-22 11:20 你假笨 阅读(1564) |
评论 (0) |
编辑 收藏
欢迎光临笔者博客
http://www.lovestblog.cn
最近两天本人在为本博实现rss发布和订阅,本来是想在前端实现xml的生成和修改,因为用as3的E4X操作xml比较方便,但是后面发现不能为元素设置CDATA值,于是只好作罢,便只能依靠后台的java来实现此功能了,当然操作xml的话,我首先想到了dom4j,dom4j操作xml还是比较方便的,即可以轻松实现我们的CDATA设置,也可以为我们任意位置插入元素提供了实现,对于在指定位置新增节点开始我有点蒙了,后面通过网上搜索资源加之自己的一些理解,而实现了此功能,下面展示了部分代码供今后参考吧:
-
public static int createXMLFile(String filename,List list){
/** *//** 返回操作结果, 0表失败, 1表成功 */
int returnValue = 0;
Document document = DocumentHelper.createDocument();
Element rssElement = document.addElement("rss");
rssElement.addAttribute("version", "2.0");
Element channelElement = rssElement.addElement("channel");
Element titleElement = channelElement.addElement("title");
titleElement.setText("你假笨(nijiaben)心情技术博客");
Element linkElement = channelElement.addElement("link");
linkElement.setText("http://www.lovestblog.cn");
Element descriptionElement = channelElement.addElement("description");
descriptionElement.setText("专注于Java,Flex技术开发研究");
Element languageElement = channelElement.addElement("language");
languageElement.setText("zh-cn");
Element lastBuildDateElement = channelElement.addElement("lastBuildDate");
lastBuildDateElement.setText(new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(((ArticleInfo)(list.get(0))).getCreateTime()));
for(int i=list.size()-1;i>0;i--){
ArticleInfo ainfo=(ArticleInfo)(list.get(i));
Element itemElement = channelElement.addElement("item");
Element title1Element = itemElement.addElement("title");
title1Element.setText(ainfo.getTitle());
Element description1Element = itemElement.addElement("description");
int maxLen=5000;
if(ainfo.getRssContent().length()<5000){
maxLen=ainfo.getRssContent().length();
}
description1Element.addCDATA(ainfo.getRssContent().substring(0, maxLen));
Element pubDate=itemElement.addElement("pubDate");
pubDate.setText(new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(ainfo.getCreateTime()));
Element link1Element=itemElement.addElement("link");
link1Element.setText("http://www.lovestblog.cn");
}
try{
/** *//** 将document中的内容写入文件中 */
XMLWriter writer = new XMLWriter(new FileOutputStream(path+filename));
writer.write(document);
writer.close();
/** *//** 执行成功,需返回1 */
returnValue = 1;
}catch(Exception ex){
ex.printStackTrace();
}
return returnValue;
}
posted @
2010-04-01 12:14 你假笨 阅读(3078) |
评论 (1) |
编辑 收藏