URLClassLoader类加载器 谁借莪1个温暖的怀抱¢ 2021-06-24 14:34 463阅读 0赞 从JDK源码上来看其实是URLClassLoader继承了ClassLoader,也就是说URLClassLoader把ClassLoader扩展了一下,所以可以理解成URLClassLoader功能要多点。ClassLoader只能加载classpath下面的类,而URLClassLoader可以加载任意路径下的类。他们的继承关系如下: public class URLClassLoader extends SecureClassLoader \{\} public class SecureClassLoader extends ClassLoader \{\} URLClassLoader是在java.net包下的一个类。一般动态加载类都是直接用Class.forName()这个方法,但这个方法只能创建程序中已经引用的类,并且只能用包名的方法进行索引,比如Java.lang.String,不能对一个.class文件或者一个不在程序引用里的.jar包中的类进行创建。 URLClassLoader提供了这个功能,它让我们可以通过以下几种方式进行加载: \* 文件: (从文件系统目录加载) \* jar包: (从Jar包进行加载) \* Http: (从远程的Http服务进行加载) 当class文件或者resources资源文件更新后,我们需要重新加载这些类或者Jar。从理论上来说,当应用清理了对所加载的对象的引用,那么垃圾收集器就会将这些对象给收集掉,然后我们再重新加载新的JAR文件,并创建一个新的URLClassLoader来加载。可是这里有一个问题,就是我们不知道垃圾收集器什么时候将那些未被引用的对象给收集掉,特别是在Windows中,因为在Windows中打开的文件是不可以被删除或被替换的。 在Java7的Build 48版中,URLClassLoader提供了close()这个方法,可以将打开的资源全部释放掉,这个给开发者节省了大量的时间来精力来处理这方面的问题。 URL url = new URL("file:foo.jar"); URLClassLoader loader = new URLClassLoader (new URL[] {url}); Class cl = Class.forName ("Foo", true, loader); Runnable foo = (Runnable) cl.newInstance(); foo.run(); loader.close (); // foo.jar gets updated somehow loader = new URLClassLoader (new URL[] {url}); cl = Class.forName ("Foo", true, loader); foo = (Runnable) cl.newInstance(); // run the new implementation of Foo foo.run(); 【实例1 加载磁盘上的一个class文件】 1、定义一个接口和实现类: ITest.java package classLoad; public interface ITest \{ public String getStr() ; \} Test.java package classLoad; public class Test implements ITest\{ public static void main(String\[\] args) \{ \} public String getStr() \{ System.out.println("ceshi..."); return "ceshi"; \} \} 2、使用urlClassLoader: package classLoad; import java.io.File; import java.net.URL; import java.net.URLClassLoader; public class URLClassLoaderTest \{ public static void main(String...strings ) throws Exception \{ File xFile=new File("F:\\\\apache-tomcat-6.0.43\\\\webapps\\\\ROOT"); URL xUrl= xFile.toURL() ; URLClassLoader ClassLoader=new URLClassLoader(new URL\[\]\{ xUrl \}); Class xClass=ClassLoader.loadClass("classLoad.Test"); System.out.println("--------加载器:"+xClass.getClassLoader()); System.out.println("=======反射调用方法"); Object xObject=xClass.newInstance(); xClass.getMethod("getStr").invoke(xObject); System.out.println("=======使用接口接收加载的对象"); ITest test = (ITest)xClass.newInstance(); test.getStr(); \} \} 输出: \--------加载器:java.net.URLClassLoader@4f0ab3f2 =======反射调用方法 ceshi... =======使用接口接收加载的对象 ceshi... 注: 1)测试时要把本地的Test.java要删除,否则根据双亲委派算法和jvm判断同一个类实例的方法,就会优先加载本地的Test实例,而不再加载F盘下的类实例。 2)把生成的Test.class文件拷贝到F:\\\\apache-tomcat-6.0.43\\\\webapps\\\\ROOT\\\\classLoad目录下。其中classLoad是包结构。 3)运行loadClass方法时,参数要使用类的全限名,URL的而路径中不包含报名。 【实例2 加载jar中的某个类】 1、把ITest.java和Test.java打包成jar文件 2、测试方法: public static void load2() throws Exception\{ URL urls\[\] = new URL\[1\]; urls\[0\] = new URL("file:D:/Test\_fat.jar"); URLClassLoader ClassLoader=new URLClassLoader(urls); Class xClass=ClassLoader.loadClass("classLoad.Test"); System.out.println("--------加载器1:"+xClass.getClassLoader()); System.out.println("=======反射调用方法1"); Object xObject=xClass.newInstance(); xClass.getMethod("getStr").invoke(xObject); System.out.println("=======使用接口接收加载的对象1"); ITest test = (ITest)xClass.newInstance(); test.getStr(); \} 输出: \--------加载器1:java.net.URLClassLoader@4f0ab3f2 =======反射调用方法1 ceshi... =======使用接口接收加载的对象1 ceshi... 【实例3 把上述方法部署到web服务器上,就会抛出异常,需要使用线程上下文类加载器】 URLClassLoader loader = new URLClassLoader(urls); //如果用于WEB应用,则需要使用以下构造方法 //URLClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
还没有评论,来说两句吧...