@snail-lb
2017-02-28T15:22:38.000000Z
字数 13003
阅读 2015
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 类的名称,不支持带有包名的类*/@Overrideprotected 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;}@Overridepublic 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 类的名称,不支持带有包名的类*/@Overrideprotected 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\Testjavac 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());}}@Overridepublic void checkPermission(Permission perm) {this.sandboxCheck(perm);}@Overridepublic void checkPermission(Permission perm, Object context) {this.sandboxCheck(perm);}}
5.定时任务
用户程序执行需要有时间限制,所以就有的定时任务,定时任务一般使用FutureTask实现,FutureTask是可取消的异步计算。FutureTask需要放入到Thread中然后Thread进行开始。