- 浏览: 199584 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
budairenqin:
budairenqin 写道carlosfu 写道膜拜一下,要 ...
写个RPC娱乐一下 -
budairenqin:
carlosfu 写道膜拜一下,要是把实现过程写个博客或者文档 ...
写个RPC娱乐一下 -
dengchang1:
好文章。 详细看了《Netty源码细节1--IO线程(Even ...
Netty源码细节3--accept(Linux os层 + Netty层代码细节) -
carlosfu:
膜拜一下,要是把实现过程写个博客或者文档就更赞了
写个RPC娱乐一下 -
budairenqin:
I_am_rookie 写道你好!能把安装包发我一下吗?我找了 ...
CentOS 6.3 X86_64安装MySQL 5.5.28 64-Bit RPM以及my.cnf配置
今天想给项目写个远程执行的小工具
1.客户端动态编译要远程执行的代码
2.通过网络将编译好的字节码传输到服务端
3.服务端留一个类装载器的接口
4.对客户端传输过来的字节码做一定修改(复杂了的不好改,修改常量池还是不难实现的,比如需要输出信息到客户端,却又想用System.out输出,修改常量池就好了,不然System.out只能输出在服务端)
5.用自定义的ClassLoader将要执行的类装载到jvm,然后执行,输出信息返回给客户端
这个工具类还是比较强大的(不过也很危险,看怎么用了),可以看到服务端的任何类的变量,也可以执行清除缓存之类的操作。
以前写过这种小玩意儿,不过是在有web容器的环境下,
现在的项目是基于netty的长连接应用,不过也好搞定,把原来代码拿来改了个把小时搞定
首先写个netty server用来接收要执行的字节码(它要跟随应用Server一同启动,也就是说同jvm)
代码太多容易打乱思路,只贴出主要代码(decode):
再写个netty的client发送字节码,代码很简单我就只贴出关键部分吧:
主要想说下动态编译那一块,把以前的代码拿出来,发现当时的自己真山炮啊,先调用编译器接口将java文件编译到硬盘上,再从硬盘读出来,放个小屁何必脱裤子呢,于是今天改了下,编译后直接返回byte[],以下是完整代码:
再写一个这样的ClassLoader,就差不多了(主要是把defineClass开放出来,注意指定父类装载器,利用双亲委派的规则来访问项目中的所有类)
要注意的是服务端将类加载到jvm后需要通过反射执行(我是写死了直接执行main方法)
比如:
我是这样使用的:
1.在当前的项目中新建一个要远程执行的类(因为这个类在你的项目中,所以编译期间你项目中所有的类对它都是可见的)
2.调用上面的netty客户端代码向远程服务器发送就可以舒服的等待返回执行结果了
下面是个小例子:
比如我的项目中有个Season类,我想看看当前服务器的Season,于是我写一个这样的远程执行代码:
执行结果:
噢啦,就写到这了,希望思路是清晰的,也希望能帮助到正需要的人
补充,我将代码从项目中剥离了出来,完整的代码到我在论坛里发的帖子中可以下载
http://www.iteye.com/topic/1128989#2386832
1.客户端动态编译要远程执行的代码
2.通过网络将编译好的字节码传输到服务端
3.服务端留一个类装载器的接口
4.对客户端传输过来的字节码做一定修改(复杂了的不好改,修改常量池还是不难实现的,比如需要输出信息到客户端,却又想用System.out输出,修改常量池就好了,不然System.out只能输出在服务端)
5.用自定义的ClassLoader将要执行的类装载到jvm,然后执行,输出信息返回给客户端
这个工具类还是比较强大的(不过也很危险,看怎么用了),可以看到服务端的任何类的变量,也可以执行清除缓存之类的操作。
以前写过这种小玩意儿,不过是在有web容器的环境下,
现在的项目是基于netty的长连接应用,不过也好搞定,把原来代码拿来改了个把小时搞定
首先写个netty server用来接收要执行的字节码(它要跟随应用Server一同启动,也就是说同jvm)
代码太多容易打乱思路,只贴出主要代码(decode):
class HotSwapPipelineFactory implements ChannelPipelineFactory { private SimpleChannelHandler messageReceivedHandler = new SimpleChannelHandler() { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { byte[] classByte = (byte[]) e.getMessage(); // decode后的字节码byte数组 // execute内部用自定义ClassLoader加载进jvm然后通过反射执行,返回值为一个String,是返回给客户端的信息,这部分代码就不贴出来了 String resultMsg = JavaClassExecuter.execute(classByte); byte[] resultByte = resultMsg.getBytes(Charset.forName(Constants.UTF8_CHARSET)); ChannelBuffer buffer = ChannelBuffers.buffer(resultByte.length); buffer.writeBytes(resultByte); e.getChannel().write(buffer); } }; @Override public ChannelPipeline getPipeline() throws Exception { return addHandlers(Channels.pipeline()); } public ChannelPipeline addHandlers(ChannelPipeline pipeline) { if (null == pipeline) { return null; } // 这个decoder主要应对消息不完整的情况,虽然是小工具也认真对待吧 pipeline.addLast("hotSwapDecoder", new FrameDecoder() { @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { if (buffer.readableBytes() >= 4) { buffer.markReaderIndex(); // 标记ReaderIndex int msgBodyLen = buffer.readInt(); // 前四个字节存放消息(字节码)的长度 if (buffer.readableBytes() >= msgBodyLen) { ChannelBuffer dst = ChannelBuffers.buffer(msgBodyLen); buffer.readBytes(dst, msgBodyLen); return dst.array(); // 这就是完整的字节码byte数组了 } else { buffer.resetReaderIndex(); return null; } } return null; } }); pipeline.addLast("hotSwapHandler", messageReceivedHandler); return pipeline; }
再写个netty的client发送字节码,代码很简单我就只贴出关键部分吧:
// Connection established successfully Channel channel = future.getChannel(); channel.setInterestOps(Channel.OP_READ_WRITE); // 编译参数 List<String> otherArgs = Arrays.asList("-classpath", HotSwapClient.class.getProtectionDomain().getCodeSource().getLocation().toString()); // 编译 byte[] classByte = JavacTool.callJavac(otherArgs, "com.XXX.HotSwap"); ChannelBuffer buffer = ChannelBuffers.buffer(classByte.length + 4); buffer.writeInt(classByte.length); buffer.writeBytes(classByte); channel.write(buffer);
主要想说下动态编译那一块,把以前的代码拿出来,发现当时的自己真山炮啊,先调用编译器接口将java文件编译到硬盘上,再从硬盘读出来,放个小屁何必脱裤子呢,于是今天改了下,编译后直接返回byte[],以下是完整代码:
public class JavacTool { // java文件的存放路径 public final static String JAVA_FILES_PATH = System.getProperty("user.dir") + "/src/test/java/"; private final static JavacTool JAVAC_TOOL = new JavacTool(); /** * @param classNames 类的全限定名称 * @return */ public static byte[] callJavac(String... classNames) { return callJavac(null, classNames); } /** * @param otherArgs 其他参数,已有参数包括"-verbose" * @param classNames 类的全限定名称 * @return */ public static byte[] callJavac(List<String> otherArgs, String... classNames) { // standardJavaFileManager实际类型 : com.sun.tools.javac.file.JavacFileManager javax.tools.StandardJavaFileManager standardJavaFileManager = null; ClassFileManager fileManager = null; try { // compiler实际类型:com.sun.tools.javac.api.JavacTool javax.tools.JavaCompiler javac = javax.tools.ToolProvider.getSystemJavaCompiler(); standardJavaFileManager = javac.getStandardFileManager(null, null, null); fileManager = JAVAC_TOOL.new ClassFileManager(standardJavaFileManager); for (int i = 0; i < classNames.length; ++i) { classNames[i] = JAVA_FILES_PATH + classNames[i].replace(".", "/") + ".java"; } Iterable<? extends javax.tools.JavaFileObject> iterable = standardJavaFileManager.getJavaFileObjects(classNames); // 相当于命令行调用javac时的参数 List<String> args = new ArrayList<String>(); args.add("-verbose"); if (otherArgs != null) { for (String arg : otherArgs) { args.add(arg); } } CompilationTask javacTaskImpl = javac.getTask(null, fileManager, null, args, null, iterable); // 编译,调用com.sun.tools.javac.main.compile(String[], Context, List<JavaFileObject>, Iterable<? extends Processor>) if (javacTaskImpl.call()) { return fileManager.getJavaClassObject().getBytes(); } else { return null; } } catch (Exception e) { e.printStackTrace(); } finally { if (standardJavaFileManager != null) try { standardJavaFileManager.close(); } catch (IOException e) { e.printStackTrace(); } if (fileManager != null) try { fileManager.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } // 编译器内部会回调这个内部类的getJavaFileForOutput方法 class ClassFileManager extends ForwardingJavaFileManager<javax.tools.StandardJavaFileManager> { private JavaClassObject jclassObject; public JavaClassObject getJavaClassObject() { return jclassObject; } protected ClassFileManager(StandardJavaFileManager fileManager) { super(fileManager); } @Override public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) { jclassObject = new JavaClassObject(className, kind); return jclassObject; } } // 这个内部类大有用处哇,编译器内部会回调openOutputStream()这个被重写的方法,拿到你定义的输出流,将字节码写入 class JavaClassObject extends SimpleJavaFileObject { protected final ByteArrayOutputStream bos = new ByteArrayOutputStream(); public JavaClassObject(String name, JavaFileObject.Kind kind) { super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind); } public byte[] getBytes() { return bos.toByteArray(); } @Override public OutputStream openOutputStream() throws IOException { return bos; } } }
再写一个这样的ClassLoader,就差不多了(主要是把defineClass开放出来,注意指定父类装载器,利用双亲委派的规则来访问项目中的所有类)
public class HotSwapClassLoader extends ClassLoader { public HotSwapClassLoader() { super(HotSwapClassLoader.class.getClassLoader()); } public Class<?> loadByte(byte[] classByte) { return defineClass(null, classByte, 0, classByte.length); } }
要注意的是服务端将类加载到jvm后需要通过反射执行(我是写死了直接执行main方法)
比如:
Method method = clazz.getMethod("main", new Class[] { String[].class }); method.invoke(null, new Object[] { null });
我是这样使用的:
1.在当前的项目中新建一个要远程执行的类(因为这个类在你的项目中,所以编译期间你项目中所有的类对它都是可见的)
2.调用上面的netty客户端代码向远程服务器发送就可以舒服的等待返回执行结果了
下面是个小例子:
比如我的项目中有个Season类,我想看看当前服务器的Season,于是我写一个这样的远程执行代码:
public class HotSwap { public static void main(String[] args) { System.out.println("test:" + Season.getSeason()); } }
执行结果:
2013-02-04 23:35:58 [com.futurefleet.framework.concurrency.NamedThreadFactory]-[INFO] new thread created : HotSwapClient_Worker-thread-1, group active count : 1 2013-02-04 23:35:58 [com.futurefleet.framework.concurrency.NamedThreadFactory]-[INFO] new thread created : HotSwapClient_Boss-thread-1, group active count : 2 channelConnected [解析开始时间 /Users/fengjiachun/Documents/workspace/pandabusGateway/src/test/java/com/futurefleet/tools/hotswap/HotSwap.java] [解析已完成时间 9ms] [正在装入 /Users/fengjiachun/Documents/workspace/XXX/target/classes/com/futurefleet/framework/util/Season.class] [正在装入 java/lang/Object.class(java/lang:Object.class)] [正在装入 java/lang/String.class(java/lang:String.class)] [正在检查 com.futurefleet.tools.hotswap.HotSwap] [正在装入 java/lang/Enum.class(java/lang:Enum.class)] [正在装入 java/lang/System.class(java/lang:System.class)] [正在装入 java/io/PrintStream.class(java/io:PrintStream.class)] [正在装入 java/io/FilterOutputStream.class(java/io:FilterOutputStream.class)] [正在装入 java/io/OutputStream.class(java/io:OutputStream.class)] [正在装入 java/lang/StringBuilder.class(java/lang:StringBuilder.class)] [正在装入 java/lang/AbstractStringBuilder.class(java/lang:AbstractStringBuilder.class)] [正在装入 java/lang/CharSequence.class(java/lang:CharSequence.class)] [正在装入 java/io/Serializable.class(java/io:Serializable.class)] [正在装入 java/lang/Comparable.class(java/lang:Comparable.class)] [正在装入 java/lang/StringBuffer.class(java/lang:StringBuffer.class)] [已写入 string:///com/futurefleet/tools/hotswap/HotSwap.class from JavaClassObject] [总时间 557ms] test:WINTER
噢啦,就写到这了,希望思路是清晰的,也希望能帮助到正需要的人
补充,我将代码从项目中剥离了出来,完整的代码到我在论坛里发的帖子中可以下载
http://www.iteye.com/topic/1128989#2386832
发表评论
-
TCP 关于SO_RCVBUF
2015-12-23 14:53 377前几天一个技术群里的小伙伴@我 问netty中.chi ... -
JUC中Atomic class之lazySet的一点疑惑
2015-11-15 20:45 921发在并发编程网了 http://ifeve.com/juc-a ... -
写个RPC娱乐一下
2015-11-15 20:38 1653来阿里一年了一直都在做业务, 也有一些怀念以前一直撸网 ... -
JUC中Atomic class之lazySet的一点疑惑
2015-06-19 01:27 0最近再次翻netty和disrupt的源码, 发现一些地方使用 ... -
Netty源码细节3--accept(Linux os层 + Netty层代码细节)
2015-06-01 15:12 2858转自己的在公司发的文章: 前言 本菜鸟有过几年的网络IO相 ... -
Netty源码细节1--IO线程(EventLoop)
2015-06-01 14:59 7662转自己在公司的文章: ... -
Java8中用sun.misc.Contended避免伪共享(false sharing)
2014-04-18 13:58 4133关于伪共享这个概念,请先参照http://ifeve.co ... -
Java 绕过编译器检查抛出“受检查的”异常
2014-01-23 16:45 2244个别特殊情况下,我们 ... -
Netty server端执行的各个阶段源码简单分析
2013-07-01 15:16 2979简单过一下Netty3.6.6.Final ... -
关于Netty的ExecutionHandler
2013-03-16 14:32 0关于Netty的ExecutionHandler -
Java字节码框架asm快速入门
2013-01-16 21:03 8220asm是一个java的字节码 ... -
Netty Server端代码简单分析
2012-11-23 17:20 9222Netty源码简单分析: Nett ... -
Web应用下JVM从哪个类包加载指定类
2012-08-29 22:50 0以下内容来自《Spring3.x企业应用开发实战》一书,收藏下 ... -
Java虚拟机指令操作码助记符
2012-06-21 17:36 2558以下内容均来自IcyFenix等大牛翻译的Java虚拟机规范 ... -
关于package-info.java
2012-06-14 23:29 10225以前不知道有package-info.java这个类, ... -
java API的动态编译接口
2012-05-23 22:53 2355读javac源码时奇怪com.sun.tools.j ... -
com.sun.tools.javac.Launcher中使用Preferences操作Windows注册表
2012-05-20 15:17 1001OpenJDK javac中com.sun.tools.jav ... -
javac语法分析
2012-01-13 00:27 1613这年头,还有比我手欠的么?一笔一笔画出来的注释...... ... -
关于条件编译
2011-12-15 14:23 932被初始化为编译期常量的 static final 变量的引用, ... -
自定义的类装载器-从DB装载class(附上对类装载器的分析)
2011-11-25 14:31 412代码才是最实在的,先从代码开始,然后再一步一步分析: 第一步: ...
相关推荐
用了Mysql 之后,发现就没有远程跟踪的工具了.....可以远程跟踪执行的语句. 在程序中屏蔽了一些系统语句.所以很清爽,不会错过一个有用的语句,比较稳定.支持"换肤"功能.数十种不同的皮肤,给你不一样的体验.
Struts2漏洞检查工具,可快速检测struts命令执行漏洞,支持批量导入验证,存在可利用的漏洞后,可远程执行命令及文件上传等操作。方便管理人员了解其危害。
shiro远程命令执行漏洞检测工具:包括了shiro_attack_2.2和ShiroExploit.V2.51,大家可根据需要自行下载
实用工具(如 Telnet)和远程控制程序(如 Symantec 的 PC Anywhere)使您可以在远程系统上执行程序,但安装它们非常困难,并且需要您在想要访问的远程系统上安装客户端软件。PsExec 是一个轻型的 telnet 替代工具...
Apache Log4j2 远程代码执行漏洞检测工具,包含windows版和linux版。图形化 Apache Log4j2检测工具
这是用C#Winfrom写的一个小工具,利用sqlserver中的master数据库中的xp_cmdshell远程执行cmd命令。
JDWP 远程命令执行检查工具,JDWP(Java DEbugger Wire Protocol):即Java调试线协议,是一个为Java调试而设计的通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。说白了就是JVM或者类JVM的虚拟机都...
nrun 是一个用来在多个目标机器上同时运行一个简单命令或者脚本的工具。ncopy 将复制文件或者目录到目标机器,底层的访问机制是可互换的,当前支持 ssh、nsh、rsh 和本地执行模式,返回的代码和所有命令的输出都被...
phpbb 2.0.17 远程命令执行工具.rarphpbb 2.0.17 远程命令执行工具.rarphpbb 2.0.17 远程命令执行工具.rar
WinCE设备的PC端命令行远程控制工具。 将压缩包解压至任意目录中备用。 将WinCE设备通过USB连接ActiveSync,在PC端用过命令行运行相应的工具即可实现各种远程控制功能,包括dir指令,运行程序,结束进程,重启,同步...
VS2010编写,可以在运行了服务端的机子上执行命令行,并将执行结果返回客户端
windows平台运维利器!自主开发的一个批量小工具,可以远程对上百台服务器的oracle和db2数据库进行跑批.
ThinkPHP v5.x命令执行利用工具(可getshell)
QQ远程CMD执行工具就是让运程电脑执行CMD命令,用来维护系统,当远程端电脑遇到故障的时候这款工具就能够派上用场。 可通过预设指令窗口添加要执行的命令,“指令关键字”来达到自动运行对应预设CMD命令的功能;...
batssh是一个在Linux系统下的批量远程执行脚本工具 使用例子: batssh -f /tmp/all_hosts "service iptables stop
指令生成;远程执行工具.exe
Linux远程命令行工具(Remote Command Line Tools)是Linux操作系统中一种特别实用的工具,...登录远程主机后,使用者可以在远程主机上执行任意命令。 3. 配置SSH 要正确配置SSH,首先应在远程主机上运行以下命令:
经典的WINCE远程控制工具,WINCE设备与PC同步连接后,可以用它可以在桌面操作设备,比如截图等。
Linux服务器批处理远程命令执行工具。纯java实现的ssh协议(jsch),支持同时连接多台linux主机,执行相同的命令。只需配置目标主机的ip地址、用户名和密码即可实现远程操作。服务器无需配置ssh对等协议或安装任何...
winrm-cli - 一个命令行工具通过WinRM在Windows机器上远程执行命令