您的位置:首页 > 编程语言

JEE服务器端执行远程目标代码实现

2014-10-30 11:44 274 查看
相信不少开发员在测试环境时经常会遇到这类情形: 排查问题过程中,想查看内存运行详细参数,或定位运行环境一些问题,要处理这些问题,只能一次次地重新发布新的代码来作进一步调试,以排查确定问题。本文会向开发人员展示另一种简单的服务器调用执行远程目标Class的方法,以更高效地排查定位测试服务器问题。

一. 实现目标功能:



界面简介:

1. 在 "远程class地址" 栏位输入 目标需要执行的class地址

2. 点击"执行" 按钮,便会执行目标类,并将目标类的输出结果打印到页面。

二. 实现原理

1. 入口invokeRemoteClass.jsp页面

<%@page import="java.io.FileInputStream,web.WebConsole,util.HttpInputStreamUtil,java.io.InputStream,loader.JavaClassExecuter"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>远程调用类测试</title>
</head>
<body>
<%
String remoteClassUrl = request.getParameter("remoteClassUrl");
String result = "";
byte[] b = null;
if(remoteClassUrl!=null){
try{
InputStream is = HttpInputStreamUtil.readInputStreamFromUrl(remoteClassUrl);
b = new byte[is.available()];
is.read(b);
result = JavaClassExecuter.execute(b);
is.close();
}catch(Exception e){
result = e.getMessage();
}
}
%>
<form action="invokeRemoteClass.jsp" method="post">
<fieldset>
<legend>远程调用类信息:</legend>
<table>
<tr><td>远程class地址:</td><td><input size="100" name="remoteClassUrl" value="<%if(remoteClassUrl!=null){out.print(remoteClassUrl);}%>"/></td></tr>
<tr><td>输出:</td><td><div><pre><%=result%></pre></div> </td></tr>
<tr><td></td><td><input type="submit" value="执行"/></td></tr>
</table>
</fieldset>
</form>
</body>
</html>
a). 主要执行逻辑为通过HttpInputStreamUtil类读取目标执行类的InputStream

b). 将inputStream转化为byte[].

c). JavaClassExecuter.execute()方法通过SwapClassLoader将class 字节码加载到类加载器中,并执行。

2. HttpInputStreamUtil类示例

package util;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
* 根据url读取相应文件流
* @author wult
*
*/
public class HttpInputStreamUtil {
/**
* 根据url,读取出其inputstream
* @param classUrl
* @return
* @throws RuntimeException
*/
public static InputStream readInputStreamFromUrl(String classUrl) throws RuntimeException{
InputStream result = null;
URL url = null;
HttpURLConnection httpConn = null;
try {
url = new URL(classUrl);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.connect();
int code = httpConn.getResponseCode();
if(code == 200){
result = httpConn.getInputStream();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return result;
}
}


3. JavaClassExecuter 远程class执行类

package loader;

import java.lang.reflect.Method;

import web.WebConsole;

/**
* JavaClass执行工具
* @author wult
*
*/
public class JavaClassExecuter {
/**
* 执行外部传过来的代表一个Java类的Byte数组
* @param classByte 代表一个Java类的Byte数组
* @return 执行结果
*/
public static String execute(byte[] classByte) throws RuntimeException{
WebConsole.clean();
SwapClassLoader loader = new SwapClassLoader();
Class clazz = loader.loadByte(classByte);
try {
Method method = clazz.getMethod("main", new Class[] { String[].class });
method.invoke(null, new String[] { null });
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
return WebConsole.getBufferString();
}
}


4. SwapClassLoader类加载器

package loader;

/**
* 本加载器目的是为了满足重复载入类
* @author wult
*
*/
public class SwapClassLoader extends ClassLoader{
public SwapClassLoader() {
super(SwapClassLoader.class.getClassLoader());
}
public Class loadByte(byte[] classByte){
return defineClass(null, classByte, 0,classByte.length);
}
}


5. WebConsole 目标执行Class类与web之间的桥梁

package web;
/**
* web控制台
* 作为目标执行Class类与web之间的桥梁
* @author wult
*
*/
public class WebConsole {
private static StringBuffer sb = new StringBuffer();
/**
* 清除buffer
*/
public static void clean(){
sb.setLength(0);
}
/**
* 打印信息
* @param line
*/
public static void println(String line){
sb.append(line);
sb.append("\n");
}
/**
* 返回sb内容
* @return
*/
public static String getBufferString(){
return sb.toString();
}
}


6. 测试类TestRemotInvoke

package test;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;

import web.WebConsole;

public class TestRemotInvoke {
public static void main(String[] args) {
MemoryMXBean memorymbean = ManagementFactory.getMemoryMXBean();
MemoryUsage usage = memorymbean.getHeapMemoryUsage();
WebConsole.println("JVM内存运行情况: ");
WebConsole.println("初始的总内存: " + usage.getInit()/(1024*1024)+"MB");
WebConsole.println("最大可用内存: " + usage.getMax()/(1024*1024)+"MB");
WebConsole.println("已使用的内存: " + usage.getUsed()/(1024*1024)+"MB");
}
}


注:

JEE服务器端执行远程目标代码功能不推荐在正式服务器使用,仅用于测试开发即可,否则会有安全问题。

本文章力图以最简单的方法实现服务器端远程执行目标代码,欢迎读者进一步进行功能扩展。

liantian.wu/吴炼钿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: