课程咨询 :186 8716 1620      qq:2066486918

昆明Java培训 > 达内新闻 > java程序:慎用动态编译
  • java程序:慎用动态编译

    发布:昆明Java培训      来源:达内新闻      时间:2016-09-30

  • 昆明达内Java培训的老师知道,动态编译一直是java的梦想,从Java6开始支持动态编译了,可以再运行期直接编译.java文件,执行.class,并且获得相关的输入输出,甚至还能监听相关的事件。不过,我们最期望的还是定一段代码, 接编译,然后运行,也就是空中编译执行(on-the-fly),看如下代码:

    1 import java.io.IOException;

    2 import java.lang.reflect.Method;

    3 import java.net.URI;

    4 import java.util.ArrayList;

    5 import java.util.Arrays;

    6 import java.util.List;

    7

    8 import javax.tools.JavaCompiler;

    9 import javax.tools.JavaFileObject;

    10 import javax.tools.SimpleJavaFileObject;

    11 import javax.tools.StandardJavaFileManager;

    12 import javax.tools.ToolProvider;

    13

    14 public class Client17 {

    15    public static void main(String[] args) throws Exception {

    16        // Java源代码

    17        String sourceStr = "public class Hello { public String sayHello (String name) {return \"Hello,\"+name+\"!\";}}";

    18        //类名及文件名

    19        String clsName = "Hello";

    20        //方法名

    21        String methodName = "sayHello";

    22        //当前编译器

    23        JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();

    24        // Java标准文件管理器

    25        StandardJavaFileManager fm = cmp.getStandardFileManager(null, null,

    26                null);

    27        // Java文件对象

    28        JavaFileObject jfo = new StringJavaObject(clsName, sourceStr);

    29        //编译参数,类似于javac <options>中的options

    30        List<String> optionsList = new ArrayList<String>();

    31        //编译文件的存放地方,注意:此处是为Eclipse工具特设的

    32        optionsList.addAll(Arrays.asList("-d", "./bin"));

    33        //要编译的单元

    34        List<JavaFileObject> jfos = Arrays.asList(jfo);

    35        //设置编译环境

    36        JavaCompiler.CompilationTask task = cmp.getTask(null, fm, null,

    37                optionsList, null, jfos);

    38        //编译成功

    39        if (task.call()) {

    40            //生成对象

    41            Object obj = Class.forName(clsName).newInstance();

    42            Class<? extends Object> cls = obj.getClass();

    43            //调用sayHello方法

    44            Method m = cls.getMethod(methodName, String.class);

    45            String str = (String) m.invoke(obj, "Dynamic Compilation");

    46            System.out.println(str);

    47        }

    48

    49    }

    50 }

    51

    52 class StringJavaObject extends SimpleJavaFileObject {

    53    //源代码

    54    private String content = "";

    55

    56    //遵循Java规范的类名及文件

    57    public StringJavaObject(String _javaFileName, String _content) {

    58        super(_createStringJavaObjectUri(_javaFileName), Kind.SOURCE);

    59        content = _content;

    60    }

    61

    62    //产生一个URL资源路径

    63    private static URI _createStringJavaObjectUri(String name) {

    64        //注意,此处没有设置包名

    65        return URI.create("String:///" + name + Kind.SOURCE.extension);

    66    }

    67

    68    //文本文件代码

    69    @Override

    70    public CharSequence getCharContent(boolean ignoreEncodingErrors)

    71            throws IOException {

    72        return content;

    73    }

    74 }

    上面代码较多,可以作为一个动态编译的模板程序。只要是在本地静态编译能够实现的任务,比如编译参数,输入输出,错误监控等,动态编译都能实现。

    Java的动态编译对源提供了多个渠道。比如,可以是字符串,文本文件,字节码文件,还有存放在数据库中的明文代码或者字节码。汇总一句话,只要符合Java规范的就可以在运行期动态加载,其实现方式就是实现JavaFileObject接口 重写getCharContent、openInputStream、openOutputStream,或者实现JDK已经提供的两个SimpleJavaFileObject、ForwardingJavaFileObject,具体代码可以参考上个例子。

    动态编译虽然是很好的工具,让我们可以更加自如的控制编译过程,但是在我们目前所接触的项目中还是使用较少。原因很简单,静态编译已经能够帮我们处理大部分的工作,甚至是全部的工作,即使真的需要动态编译,也有 好的替代方案,比如Jruby、Groovy等无缝的脚本语言。另外,我们在使用动态编译时,需要注意以下几点:

    在框架中谨慎使用:比如要在struts中使用动态编译,动态实现一个类,它若继承自ActionSupport就希望它成为一个Action。能做到,但是debug很困难;再比如在Spring中,写一个动态类,要让它注入到Spring容器中,这是需要花费老大功 的。

    不要在要求性能高的项目中使用:如果你在web界面上提供了一个功能,允许上传一个java文件然后运行,那就等于说:"我的机器没有密码,大家都可以看看",这是非常典型的注入漏洞,只要上传一个恶意Java程序就可以让你所有的 安全工作毁于一旦。

    记录动态编译过程:建议记录源文件,目标文件,编译过程,执行过程等日志,不仅仅是为了诊断,还是为了安全和审计,对Java项目来说,空中编译和运行时很不让人放心的,留下这些依据可以很好地优化程序。

    了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

    推荐文章

上一篇:java开发:易变业务使用脚本语言编写

下一篇:避免instanceof非预期结果

最新开班日期  |  更多

Java--零基础全日制班

Java--零基础全日制班

开班日期:11/30

Java--零基础业余班

Java--零基础业余班

开班日期:11/30

Java--周末提升班

Java--周末提升班

开班日期:11/30

Java--零基础周末班

Java--零基础周末班

开班日期:11/30

  • 网址:http://km .java.tedu.cn      地址:昆明市官渡区春城路62号证券大厦附楼6楼
  • 课程培训电话:186 8716 1620      qq:2066486918    全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56