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

    相信不少开发员在测试环境时经常会遇到这类情形: 排查问题过程中,想查看内存运行详细参数,或定位运行环境一些问题,要处理这些问题,只能一次次地重新发布新的代码来作进一步调试,以排查确定问题。本文会向开发人员展示另一种简单的服务器调用执行远程目标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/吴炼钿

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值