English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Em alguns casos, precisamos gerar código java dinamicamente, compilar dinamicamente e então executar o código. A API JAVAAPI fornece as ferramentas (JavaCompiler) para compilar dinamicamente. A seguir, apresentamos um exemplo simples de como usar o JavaCompiler para compilar código java dinamicamente.
1. Obter JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Obter o compilador java fornecido pelo JDK, se não fornecer o compilador, retorna null;
2. Compilar
//Obter a classe de gerenciador de arquivos java StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); //Obter o iterador de objetos de arquivo java Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files); //Definir parâmetros de compilação ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //Configurar o classpath ops.add("-classpath); ops.add(CLASS_PATH); //Obter a tarefa de compilação JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it); //Executar a tarefa de compilação task.call();
Quando o código-fonte que vamos compilar se referir a outro código, precisamos configurar o caminho do código referenciado para-no classpath, senão o compilação falhará.
3. Executar
//Nome da classe a ser carregada String className = "xxx.xxx.xxx"; //Obter o carregador de classe ClassLoader classLoader = XXX.class.getClassLoader(); //Carregar classe Class<?> cls = classLoader.loadClass(className); //Nome do método chamado String methodName = "execute"; //Tipo de array de parâmetros de método Class<?>[] paramCls = {...}; //Obter método Method method = cls.getDeclaredMethod(methodName , paramCls); //Criar instância da classe Object obj = cls.newInstance(); //Parâmetros do método Object[] params = {...}; //Chamar método Object result = method.invoke(obj, params);
IV. Código completo
//ClassUtil.java import java.io.FileWriter; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ClassUtil { private static final Log logger = LogFactory.getLog(ClassUtil.class); private static JavaCompiler compiler; static{ compiler = ToolProvider.getSystemJavaCompiler(); } /** * Obter caminho do arquivo Java * @param file * @return */ private static String getFilePath(String file){ int último1 = file.lastIndexOf('/'); int último2 = file.lastIndexOf('\'); return file.substring(0, último1>último2?último1:último2)+File.separator character; } /** * Compilar arquivo java * @param ops 编译参数 * @param files Arquivos de compilação */ private static void javac(List<String> ops,String... files){ StandardJavaFileManager manager = null; try{ manager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it); task.call(); if(logger.isDebugEnabled()){ for (String file:files) logger.debug("Compilar Arquivo Java:") + file); } } catch(Exception e){ logger.error(e); } finally{ if(manager!=null){ try { manager.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * Gerar arquivo java * @param file Nome do arquivo * @param source java代码 * @throws Exception */ private static void escreverArquivoJava(String file,String source)throws Exception{ if(logger.isDebugEnabled()){ logger.debug("Escrever Código Fonte Java em:")+file); } BufferedWriter bw = null; try{ File dir = new File(getFilePath(file)); if(!dir.exists()) dir.mkdirs(); bw = new BufferedWriter(new FileWriter(file)); bw.write(source); bw.flush(); } catch(Exception e){ lançar e; } finally{ if(bw!=null){ bw.close(); } } } /** * Carregar classe * @param nome Nome da classe * @return */ private static Class<?carregar(String nome){ Class<?> cls = null; ClassLoader classLoader = null; try{ classLoader = ClassUtil.class.getClassLoader(); cls = classLoader.loadClass(name); if(logger.isDebugEnabled()){ logger.debug("Load Class["+name+"] by ",+classLoader); } } catch(Exception e){ logger.error(e); } return cls; } /** * 编译代码并加载类 * @param filePath java代码路径 * @param source java代码 * @param clsName 类名 * @param ops 编译参数 * @return */ public static Class<?> loadClass(String filePath, String source, String clsName, List<String> ops){ try { writeJavaFile(CLASS_PATH+filePath,source); javac(ops,CLASS_PATH+filePath); return load(clsName); } catch (Exception e) { logger.error(e); } return null; } /** * 调用类方法 * @param cls 类 * @param methodName 方法名 * @param paramsCls 方法参数类型 * @param params 方法参数 * @return */ public static Object invoke(Class<?> cls, String methodName, Class<?>[] paramsCls, Object[] params){ Object result = null; try { Method method = cls.getDeclaredMethod(methodName, paramsCls); Object obj = cls.newInstance(); result = method.invoke(obj, params); } catch (Exception e) { logger.error(e); } return result; } }
Cinco, teste
public class ClassUtilTest { private static final Log logger = LogFactory.getLog(ClassUtilTest.class); public static void main(String args[]){ StringBuilder sb = new StringBuilder(); sb.append("package com.even.test;"); sb.append("import java.util.Map;\nimport java.text.DecimalFormat;\n"); sb.append("public class Sum{\n"); sb.append("private final DecimalFormat df = new DecimalFormat(\"#.#####\");\n"); sb.append("public Double calculate(Map<String,Double> data){\n"); sb.append("double d = (30*data.get(\"f1\") + 20*data.get(\"f2\") + 50*data.get(\"f3\"))/100;\n"); sb.append("return Double.valueOf(df.format(d));}}\n"); //Definir parâmetros de compilação ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //Compilar código, retornar class Class<?> cls = ClassUtil.loadClass("/com/even/test/"Sum.java",sb.toString(),"com.even.test.Sum",ops); //Preparar dados de teste Map<String,double> data = new HashMap<String,double>(); data.put("f1", 10.0); data.put("f2", 20.0); data.put("f3", 30.0); //Executar método de teste Object result = ClassUtil.invoke(cls, "calculate", new Class[]{Map.class}, new Object[]{data}); //Resultados de Saída logger.debug(data); logger.debug("(30*f1+20*f2+50*f3)/100 = "+result); }
Resultados do Teste
16:12:02.860 DEBUG com.even.tools.ClassUtil - Escrever Código Fonte Java para: .../classes//com/even/test/Sum.java 16:12:03.544 DEBUG com.even.tools.ClassUtil - Compilar Arquivo Java:.../classes//com/even/test/Sum.java 16:12:03.545 DEBUG com.even.tools.ClassUtil - Carregar Classe[com.even.test.Sum] por sun.misc.Launcher$AppClassLoader@73d16e93 16:12:03.547 DEBUG com.even.test.ClassUtilTest - {f1=10.0, f2=20.0, f3=30.0} 16:12:03.547 DEBUG com.even.test.ClassUtilTest - (30*f1+20*f2+50*f3)/100 = 22.0
Resumo
Isso é tudo sobre o exemplo de código de execução dinâmica de compilação de código em tempo de execução de Java neste artigo. Espero que ajude. Os amigos interessados podem continuar a consultar o site:
Compartilhamento de código de compilação dinâmica e carregamento de código em tempo de execução de programação Java
Exemplo de código de problema de distância de edição da programação dinâmica em Java
Explicação detalhada da implementação de referências e proxy dinâmicos em Java
Bem-vindo a deixar comentários sobre pontos insuficientes. Agradecemos o apoio dos amigos ao site!
Declaração: O conteúdo deste artigo é extraído da internet, pertence ao autor original, é contribuído e carregado voluntariamente pelos usuários da internet, o site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade legal. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas. Apenas após a verificação, o site deletará o conteúdo suspeito de infringência de direitos autorais.)