Java动态编译

目的:可以从文件中读取函数代码,动态的编译代码、加载到内存中

参考链接:https://blog.csdn.net/lmy86263/article/details/59742557

代码附加注释

package jit;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;

public class JITtest {
    //构建文件链表,保存文件中类名和函数
	private static Map<String, JavaFileObject> fileObjects = new ConcurrentHashMap<>(); 
	public static void main( String[] args ) throws IOException { 
		//读取文本内容
		StringBuilder fileTxt = new StringBuilder();
		 File file = new File("/home/liuzao/fileTest");
        try{
            //构造一个BufferedReader类来读取文件
            BufferedReader br = new BufferedReader(new FileReader(file));
            String s = null;
            while((s = br.readLine())!=null){
                //使用readLine方法,一次读一行并附加换行符
            	fileTxt.append(s + System.lineSeparator());
            }
            br.close();    
        }catch(Exception e){
            e.printStackTrace();
        }
        
        //构建函数
        String codeStart = "import jit.*;\n" + 
                                "public class Man{\n" + 
                                "public void hello(){\n" +
                                "helloworld hello = new helloworld();\n" ;
		String codeUser = fileTxt.toString();
		String codeEnd = "}\n" + 
							"}"; 
	    String code = codeStart + codeUser +codeEnd;

		//获取JavaCompiler,JDK提供的java编译器,如果没有提供编译器,则返回null;
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
		
		//工具的诊断的接口
		DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>(); 
		
		//获取java文件管理类
		JavaFileManager javaFileManager = new MyJavaFileManager(compiler.getStandardFileManager(collector, null, null)); 
		
		//设置编译参数
		List<String> options = new ArrayList<>(); 
		options.add("-target"); 
		options.add("1.8"); 

		//正则表达是提取类名字
		Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s*"); 
		Matcher matcher = CLASS_PATTERN.matcher(code); 
		String cls; 
		if(matcher.find()){ 
			cls = matcher.group(1); 
		} else { 
			throw new IllegalArgumentException("No such class name in " + code); 
		} 

		//所有超级接口
		JavaFileObject javaFileObject = new MyJavaFileObject(cls, code); 
		
		// 获取编译任务
		//在其他实例都已经准备完毕后, 构建编译任务
		Boolean result = compiler.getTask(null, javaFileManager, collector, options, null, Arrays.asList(javaFileObject)).call(); 
		
		//获取类加载器
		ClassLoader classloader = new MyClassLoader(); 
		
		//加载类
		Class<?> clazz = null; 
		try { 
			clazz = classloader.loadClass(cls); 
		} catch (ClassNotFoundException e) { 
			e.printStackTrace(); 
		} 
						
		
		//调用方法名称
		Method method = null; 
		try { 
			method = clazz.getMethod("hello"); 
		} catch (NoSuchMethodException e) { 
			e.printStackTrace(); 
		} 
		
		//调用方法
		try { 
			method.invoke(clazz.newInstance());  
		} catch (IllegalAccessException e) { 
			e.printStackTrace(); 
		} catch (InvocationTargetException e) { 
			e.printStackTrace(); 
		} catch (InstantiationException e) { 
			e.printStackTrace(); 
		} 
		
		/*
		//获取类中方法并反射使用方法
		Method[] method = clazz.getDeclaredMethods();
		try {
			if(method[0].getName().equals("hello"))
			{
				method[0].invoke(clazz.newInstance());
			}
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
				| InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
	} 
	
	/**
	 * 编译代码并加载类
	 * @author liuzao
	 *
	 */
	public static class MyClassLoader extends ClassLoader { 
		@Override 
		protected Class<?> findClass(String name) throws ClassNotFoundException { 
			JavaFileObject fileObject = fileObjects.get(name); 
			if(fileObject != null){ 
				byte[] bytes = ((MyJavaFileObject)fileObject).getCompiledBytes(); 
				return defineClass(name, bytes, 0, bytes.length); 
			} try{ 
				return ClassLoader.getSystemClassLoader().loadClass(name); 
			} catch (Exception e) { 
				return super.findClass(name); 
			} 
		} 
	} 
	
	public static class MyJavaFileObject extends SimpleJavaFileObject { 
		private String source; 
		private ByteArrayOutputStream outPutStream; 
		// 该构造器用来输入源代码
		public MyJavaFileObject(String name, String source) { 
			// 1、先初始化父类,由于该URI是通过类名来完成的,必须以.java结尾。
			// 2、如果是一个真实的路径,比如是file:///test/demo/Hello.java则不需要特别加.java 
			// 3、这里加的String:///并不是一个真正的URL的schema, 只是为了区分来源
			super(URI.create("String:///" + name + Kind.SOURCE.extension), Kind.SOURCE); 
			this.source = source; 
		} 
		
		// 该构造器用来输出字节码
		public MyJavaFileObject(String name, Kind kind){ 
			super(URI.create("String:///" + name + kind.extension), kind); 
			source = null; 
		} 
		
		@Override 
		//调用ClientCodeWrapper$WrappedFileObject对象中的filename.getCharContent(false)方法来读取要编译的源码
		public CharSequence getCharContent(boolean ignoreEncodingErrors){ 
			if(source == null){ throw new IllegalArgumentException("source == null"); 
			} 
			return source; 
		} 
		
		@Override public OutputStream openOutputStream() throws IOException { 
			outPutStream = new ByteArrayOutputStream(); 
			return outPutStream; 
		} 
		
		// 获取编译成功的字节码byte[]
		public byte[] getCompiledBytes(){ 
			return outPutStream.toByteArray(); 
		} 
	} 
	
	public static class MyJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> { 
		protected MyJavaFileManager(JavaFileManager fileManager) { 
			super(fileManager); 
		} 
		
		@Override public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException { 
			JavaFileObject javaFileObject = fileObjects.get(className); 
			if(javaFileObject == null){ 
				super.getJavaFileForInput(location, className, kind); 
			} 
			return javaFileObject; 
		} 
		
		@Override
		public JavaFileObject getJavaFileForOutput(Location location, String qualifiedClassName, JavaFileObject.Kind kind, FileObject sibling) throws IOException { 
			JavaFileObject javaFileObject = new MyJavaFileObject(qualifiedClassName, kind); 
			fileObjects.put(qualifiedClassName, javaFileObject); 
			return javaFileObject; 
		} 
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值