Java动态编译和动态加载详解

一.动态编译

在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码。JAVA API提供了相应的工具(JavaCompiler)来实现动态编译。

//获取JavaCompiler JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

//获取java文件管理类 StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);

//获取java文件对象迭代器 Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);

//设置编译参数 ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked");

//可以指定源文件或目标文件的JDK版本 ops.add("-source")/ops.add("-target");; ops.add("1.5");

//获取编译任务:第一个null,用于输出错误的流,默认是System.err;第二个null,diagnosticListener: 编译器的默认行为 ;第三个null,classes,参与编译的class,为null时表示全部

//JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);

//执行编译任务 task.call();

动态编译几个关键类

类名

作用

创建方式

JavaCompiler

动态编译的入口,也是基础类

ToolProvider.getSystemJavaCompiler()

StandardJavaFileManager

java文件管理类

compiler.getStandardFileManager

Iterable

文件对象迭代器

manager.getJavaFileObjects(files)

ArrayList<String> 

编译参数

new ArrayList<String>()

踩坑记

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 这句代码在IDEA中运行正常,然后打成jar包在桌面双击运行时得到的是null

问题解决:

查看ToolProvider源码可知,是因为找不到tools.jar---》将tools.jar复制到jre/lib下

二.动态加载

JAVA中的类加载:双亲委派模式

URL  url = new URL("file:" + CLASS_PATH);

ClassLoader  classLoader = new URLClassLoader(new URL[]{url});

Class<?> cls = classLoader.loadClass(name);

Method method = cls.getDeclaredMethod(String methodName)

Object obj = cls.newInstance();

Object result = method.invoke(Object obj, Object[] params);

class.forName()和classLoader区别:

 //Class.forName(String className)  这是1.8的源码

 public static Class<?> forName(String className) throws ClassNotFoundException {

        Class<?> caller = Reflection.getCallerClass();

        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);    

}      

//注意第二个参数,是指Class被loading后是不是必须被初始化。 不初始化就是不执行static的代码即静态代码 class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。

而classLoader只干一件事情,就是将.class文件加载到jvm中。

扩展:TOMCAT中的类加载架构

1、JAVA_HOME:设置为JDK的安装目录,如D:\java\jdk1.8。一些依赖JAVA的软件通过该环境变量来获得JDK的安装目录,如大家都知道的Eclipse、Tomcat等。

2、PATH:在已有值最后加上 ;%JAVA_HOME%\bin ,其中;是分隔符,用于分开每个目录,其中%JAVA_HOME%则是引用上面的JAVA_HOME环境变量的值,可以直接用JDK的安装目录代替,下面的CLASSPATH类似。执行路径(也就是PATH环境变量的值)是只操作系统搜索本地可执行文件的目录列表,在shell中执行命令时,它会在执行路径中查找所对应的程序。所以在PATH中加入了%JAVA_HOME%\bin目录后,在shell中就可以执行javac或者java命令。

3、CLASSPATH:设置值为.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; 注意其中的标点符号,其中第一个点“.”表示当前目录,而分号“;”则是分隔符。 这个CLASSPATH为JVM加载类的目录,比如HelloWorld.java中有import其他类,用javac编译时它会在CLASSPATH中去找你所import的类,如果找不到则出现编译错误。 另外在使用java时使用-classpath 参数可以指定要加载类的目录,比如命令行执行:C:/UsersJakey>java -classpath D:\temp HelloWorld  ,这样就可以当命令行在C盘时执行D盘目录中的JAVA类。

猜你喜欢

转载自blog.csdn.net/wowwilliam0/article/details/83057728