@snail-lb
2017-02-28T23:22:38.000000Z
字数 13003
阅读 1732
java进阶
(使用多线程来执行系统中的Class文件,这个类中的方法有参数,有返回值)
package com.cn.oj_java_my;
import java.io.File;
import java.io.FileInputStream;
public class MyClassLoader extends ClassLoader {
/** 默认classPath */
private String classPath;
/** class的实例 **/
private Class<?> cla;
/**
* 构造函数
* @param classPath
*/
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
/**
* @param className 类的名称,不支持带有包名的类
*/
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
return loadClass(classPath, className);
}
/**
* 更改类加载器加载类的classpath,在指定路径下加载制定的类class文件
*
* @param classPath
* 要加载的类路径
* @param className
* 要加载的类名 只能加载不含包的类.
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Class<?> loadClass(String classPath, String className)
throws ClassNotFoundException{
File classFile = new File(classPath + "\\" + className + ".class");
byte[] mainClass = new byte[(int) classFile.length()];
try {
FileInputStream in = new FileInputStream(classFile);
in.read(mainClass);
in.close();
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException(className);
}
Class<?> cla = super.defineClass(className, mainClass, 0, mainClass.length);
this.cla = cla;
return cla;
}
/**
* 获取classPath
*
* @return String classPath
*/
public String getClassPath() {
return classPath;
}
/**
* 实例化当前类 此方法必须在类加载之后执行
* @param className
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public Object newInstance(String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
if(this.cla == null){
throw new RuntimeException("类" + className + "没有加载");
}
return this.cla.newInstance();
}
}
package com.cn.oj_java_my;
import java.lang.reflect.Method;
/**
* 通过反射获取类中响应的方法属性
*
* @author lvbiao
*
*/
public class MyObject {
private String classPath;
private String className;
/**自定义类加载器**/
private MyClassLoader mcl;
//类初始化
public void init(String classPath,String className){
this.classPath = classPath;
this.className = className;
mcl = new MyClassLoader(classPath);
}
public Method getMethod(String methodName) throws Exception {
if(mcl == null){
throw new RuntimeException(this.className + "没有初始化");
}
Class<?> cla = mcl.findClass(className);
Method method = cla.getMethod(methodName, String.class);
method.setAccessible(true);
return method;
}
public Object newInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return mcl.newInstance(className);
}
}
package com.cn.oj_java_my;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
public class MyTask implements Callable<Object> {
private String parameters;
private String classPath;
private String className;
public MyTask(String parameters) {
this.parameters = parameters;
}
@Override
public Object call() throws Exception {
// 这里使用反射获取main函数
MyObject mo = new MyObject();
if(classPath.equals(null)){
throw new RuntimeException("没有设置类路径");
}
if(className.equals(null)){
throw new RuntimeException("没有设置类名称");
}
mo.init(classPath, className);
//要获取的方法名称
String methodName = "test";
Method mainMethod = mo.getMethod(methodName);
//获取实例化的类
Object obj = mainMethod.invoke(mo.newInstance(), parameters);
return obj;
}
public String getClassPath() {
return classPath;
}
public void setClassPath(String classPath) {
this.classPath = classPath;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
}
package com.cn.oj_java_my;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class MyOjCore {
public static void main(String[] args) {
//设置线程池
ExecutorService executor = Executors.newCachedThreadPool();
//设置方法参数
String parameters = "asdf";
MyTask task = new MyTask(parameters);
task.setClassPath("F:\\Test");
task.setClassName("Test");
Future<Object> result = executor.submit(task);
executor.shutdown();
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("主线程在执行任务");
try {
System.out.println("task运行结果" + result.get().toString());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
5.系统中F:\Test\Test.java文件
public class Test {
public String test(String str){
System.out.println("+++"+str+"+++");
return new String("aaaaaaaaaaa");
}
}
package com.cn.ojcore.common;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 编译java文件
* @author lvbiao
*
*/
public class MyCompiler {
/**
* 批处理文件路径
* @param path
*/
public static void command(String path){
try {
Runtime run = Runtime.getRuntime();
//String path = "F:\\Test\\my1.bat";
//String path = "F:\\Test\\my1.bat";
Process process = run.exec("cmd.exe /c " + path);
InputStream in = process.getInputStream();
InputStream inError = process.getErrorStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
BufferedReader brError = new BufferedReader(new InputStreamReader(inError, "GBK"));
String error;//错误信息
while ((error = brError.readLine()) != null) {
System.out.println(error);
}
String s;
while ((s = bufferedReader.readLine()) != null) {
System.out.println(s);
}
in.close();
bufferedReader.close();
System.out.println("返回值:" + process.waitFor());
System.out.println("========================");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.cn.ojcore.common;
import java.io.File;
import java.io.FileInputStream;
public class MyClassLoader extends ClassLoader {
/** 默认classPath */
private String classPath;
/** class的实例 **/
private Class<?> cla;
/**
* 构造函数
* @param classPath
*/
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
/**
* @param className 类的名称,不支持带有包名的类
*/
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
return loadClass(classPath, className);
}
/**
* 更改类加载器加载类的classpath,在指定路径下加载制定的类class文件
*
* @param classPath
* 要加载的类路径
* @param className
* 要加载的类名 只能加载不含包的类.
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Class<?> loadClass(String classPath, String className)
throws ClassNotFoundException{
File classFile = new File(classPath + "\\" + className + ".class");
byte[] mainClass = new byte[(int) classFile.length()];
try {
FileInputStream in = new FileInputStream(classFile);
in.read(mainClass);
in.close();
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException(className);
}
Class<?> cla = super.defineClass(className, mainClass, 0, mainClass.length);
this.cla = cla;
return cla;
}
/**
* 获取classPath
*
* @return String classPath
*/
public String getClassPath() {
return classPath;
}
/**
* 实例化当前类 此方法必须在类加载之后执行
* @param className
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public Object newInstance(String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
if(this.cla == null){
throw new RuntimeException("类" + className + "没有加载");
}
return this.cla.newInstance();
}
}
package com.cn.ojcore.common;
import java.lang.reflect.Method;
/**
* 通过反射获取类中响应的方法属性
*
* @author lvbiao
*
*/
public class MyObject {
private String classPath;
private String className;
/**自定义类加载器**/
private MyClassLoader mcl;
//类初始化
public void init(String classPath,String className){
this.classPath = classPath;
this.className = className;
mcl = new MyClassLoader(classPath);
}
public Method getMethod(String methodName) throws Exception {
if(mcl == null){
throw new RuntimeException(this.className + "没有初始化");
}
Class<?> cla = mcl.findClass(className);
// Method method = cla.getMethod(methodName, (new Object[0]).getClass());
Method method = cla.getMethod(methodName, String[].class);
method.setAccessible(true);
return method;
}
public Object newInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return mcl.newInstance(className);
}
}
package com.cn.ojcore.common;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.Console;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;
import java.util.concurrent.Callable;
public class MyTask implements Callable<Object> {
private String[] parameters;
private String classPath;
private String className;
private String methodName;
public MyTask(String classPath, String className, String methodName) {
this.classPath = classPath;
this.className = className;
this.methodName = methodName;
}
// 设置参数
public void setParameter(String[] parameters) {
this.parameters = parameters;
}
public Object call() throws Exception{
return this.invoke();
}
// 有参数的方法
public Object invoke() throws Exception {
// 这里使用反射获取函数
MyObject mo = new MyObject();
//初始化,设置类路径及类名称
mo.init(classPath, className);
Method mainMethod = mo.getMethod(methodName);
Object obj;
//调用方法,获取返回值
if(Modifier.isStatic(mainMethod.getModifiers())) {
//静态方法的调用
// obj = mainMethod.invoke(null, new Object[] { parameters });
//输入重定向
System.setIn(new BufferedInputStream(new ByteArrayInputStream("abc aaa".getBytes())));
obj = mainMethod.invoke(null, (Object)parameters);
}else{
//非静态方法的调用
// obj = mainMethod.invoke(mo.newInstance(), new Object[] { parameters });
obj = mainMethod.invoke(mo.newInstance(), (Object)parameters);
}
return obj;
}
}
package com.cn.ojcore;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.cn.ojcore.common.MyCompiler;
import com.cn.ojcore.common.MyTask;
public class MyOjCore {
/**类路径**/
private static String classPath = "F:\\mavenProject\\MyOjCore\\Test";
/**类名称**/
private static String className = "Test2";
/**调用方法名称**/
private static String methodName = "main";
/**批操作文件文件名**/
private static String batName = "mytest.bat";
public static void main(String[] args) {
//设置线程池
ExecutorService executor = Executors.newCachedThreadPool();
//编译java文件
MyCompiler.command(classPath + "\\" + batName);
//设置方法参数
String[] parameters = {"Bob","Tom"};
MyTask task = new MyTask(classPath, className, methodName);
task.setParameter(parameters);
Future<Object> result = executor.submit(task);
executor.shutdown();
try {
Object obj = result.get();
if(obj == null){
System.out.println("返回值为空,没有返回值");
}else{
System.out.println("task运行结果" + result.get().toString());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
public class Test2 {
public static void main(String[] args){
java.util.Scanner ac = new java.util.Scanner(System.in);
String str1 = ac.nextLine();
System.out.println(str1);
}
}
F:
cd F:\mavenProject\MyOjCore\Test
javac Test2.java
F:\mavenProject\MyOjCore>F:
F:\mavenProject\MyOjCore>cd F:\mavenProject\MyOjCore\Test
F:\mavenProject\MyOjCore\Test>javac Test2.java
返回值:0
++++++++++++++++++++
abc aaa
返回值为空,没有返回值
后续代码较多,欢迎访问
我的git
在整个java判题内核的编写过程中,主要有以下几个技术难点,现在对这些做一个总结,以便以后进行查阅。
1.获取系统的输入输出。
比如现在我要运行一个用户提交的程序,平常我们都是在Eclipse中直接运行,如果有运行中的输入输出,我们可以直接在控制台进行输入输出,但是现在这个程序托管给了我们,需要我们自己进行运行,这就需要我们在程序中提前将输入设置好,在运行之前将其输入。这就需要用到System.setIn(),System.setOut()等方法,具体用法见文档。
System.setIn(new BufferedInputStream(new ByteArrayInputStream(normInputBuffer.toString().getBytes())));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos));
2.执行cmd命令
java文件的编译工作需要cmd控制台中执行javac命令进行,执行cmd命令方式:
Runtime run = Runtime.getRuntime();
Process process = run.exec("cmd.exe /c " + order);
3.class文件的导入
由于我们的class文件是在程序执行过程中生成的,所以需要我们手动的将class文件导入到jvm中,导入方法:
我们的导入类继承ClassLoader类,然后调用父类中defineClass方法
public class MyClassLoader extends ClassLoader {
public Class<?> loadClass(byte[] classFile, String className) {
Class<?> cla = super.defineClass(className, classFile, 0, classFile.length);
return cla;
}
}
另外还需要注意,不同进程中的类是不可以通用的,就是说Class对象是不能通过socket传送的。
4.安全
在执行用户代码的时候,我们需要将其放入到沙箱中进行执行,并给与最低权限,以防发生安全事故。设置安全管理器:
security = System.getSecurityManager();
if (security == null) {
System.setSecurityManager(new MySecurityManager());
}
自定义安全策略:
public class MySecurityManager extends SecurityManager{
/**
* 重写强行退出检测
* 防止用户自行终止虚拟机的运行,但是调用程序端可以执行退出
* */
public void checkExit(int status) {
throw new SecurityException("Exit On Client Is Not Allowed!");
}
/**
* 策略权限查看
* 当执行操作时调用,如果操作允许则返回,操作不允许抛出SecurityException
* */
private void sandboxCheck(Permission perm) throws SecurityException {
// 设置只读属性
if (perm instanceof SecurityPermission) {
//安全性
if (perm.getName().startsWith("getProperty")) {
return;
}
} else if (perm instanceof PropertyPermission) {
//属性
if (perm.getActions().equals("read")) {
return;
} else{
throw new SecurityException(perm.toString());
}
} else if (perm instanceof FilePermission) {
//文件操作
if (perm.getActions().equals("read") || perm.getActions().equals("execute")) {
return;
}else{
throw new SecurityException(perm.toString());
}
} else if (perm instanceof ReflectPermission){
//反射
return;
}else if(perm instanceof RuntimePermission){
//运行时安全
return;
}
else if(perm instanceof SocketPermission){
//Socket权限
if (perm.getActions().equals("accept") ||
perm.getActions().equals("connect") ||
perm.getActions().equals("listen") ||
perm.getActions().equals("resolve")
) {
return;
}
}else if(perm instanceof NetPermission){
//网络
if(perm.implies(new NetPermission("specifyStreamHandler"))){
//在构造 URL 时指定流处理程序的能力
return;
}else{
throw new SecurityException(perm.toString());
}
}else{
throw new SecurityException(perm.toString());
}
}
@Override
public void checkPermission(Permission perm) {
this.sandboxCheck(perm);
}
@Override
public void checkPermission(Permission perm, Object context) {
this.sandboxCheck(perm);
}
}
5.定时任务
用户程序执行需要有时间限制,所以就有的定时任务,定时任务一般使用FutureTask实现,FutureTask是可取消的异步计算。FutureTask需要放入到Thread中然后Thread进行开始。