简要介绍一下urlClassloader 的作用。一般我们在开发中会经常用自已的方式加载与管理类。特别是在设计一套系统时。urlClassloader是一个不错的选择。他实现了从硬盘上以绝对路径的方式加载类。tomcat,jboss底层就采用了这样的方式来管理与加载自身的类。如tomcat api jar 等。在tomcat7中。urlClassloader是作为配置加载类的一部分存在的,他不仅仅加载单个class,他还可以加载一个jar.如下实例让我们来认识一下urlClassloader. 这里只是初探。
HelloWorld 类
public class HelloWorld
{
public String sayHello(String s)
{
return s + " : helloWorld!!!";
}
public static void main(String []args)
{
System.out.println("HelloWorld");
}
}
TClassLoader 类
public class TClassLoader
{
public String [] getArray(int m)
{
if(m <= 0)
{
return null;
}
String iStr[] = new String[m];
for(int i=0; i<m; i++ )
{
iStr[i] = "a" + i;
}
return iStr;
}
}
将上述两个类通过控制台或eclipse打包成jar文件。分别放在某个盘符的某个目录下。
接下来就是一个测试类。来实现jar的装载与调用。
package com.taobao.util;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Set;
public class ClassLoaderUtil extends URLClassLoader {
public ClassLoaderUtil(URL [] reposities) {
// TODO Auto-generated constructor stub
super(reposities);
}
public ClassLoaderUtil(URL [] reposities , ClassLoader parent)
{
super(reposities,parent);
}
public static void main(String []args) throws Exception
{
//自定义UrlClassLoader
ClassLoaderUtil util = null;
String urls[] = new String[]{"E:/urlclassloader/hello/HelloWorld.jar","E:/urlclassloader/tclass/TClassLoader.jar"};
Set<URL> s = new HashSet<URL>();
for(int i=0; i<urls.length; i++)
{
File f = new File(urls[i]);
f = new File(f.getCanonicalPath());
if(!f.exists() && !f.canRead())
{
continue;
}
URL url = f.toURI().toURL();
s.add(url);
}
URL [] u = s.toArray(new URL[s.size()]);
util = new ClassLoaderUtil(u);
Class class1 = util.loadClass("HelloWorld");
Object ojava = class1.newInstance();
Method method = class1.getMethod("sayHello", new Class[]{String.class});
System.out.println(method.invoke(ojava, new Object[]{"abc"}));
System.out.println(ClassLoaderUtil.class.getClassLoader());
}
}
---------------------------------------------------------------------------------------------------------------------------------
-
读取配置文件中的信息
配置文件的内容:
用URLClassLoader读配置文件内容:
- import java.io.IOException;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.Properties;
- public class Testext {
- public static void main(String[] args) throws IOException {
- Properties properties = new Properties();
- URL[] urls = new URL[] { new URL("file:/"
- + System.getProperty("user.dir") + "/ravageWeb/") };
- URLClassLoader ucl = new URLClassLoader(urls);
- //ClassLoader cl = Testext.class.getClassLoader(); //这两行也可以不写
- //cl = ucl; //如果写,下面就要改为:cl.getResourceAsStream...
- properties.load(ucl.getResourceAsStream("resources/testpro.properties"));
- System.out.println(properties.getProperty("sui"));
- }
- }
遇到的问题:1. "/ravageWeb/" 中第二个 / 可写可不写。 但是若改为 "/ravageWeb/resources/" 则resources后必须加 / 否则报NullPointerException
用ClassLoader读配置文件内容:
- import java.io.IOException;
- import java.util.Properties;
- public class Testext {
- public static void main(String[] args) throws IOException {
- Properties properties = new Properties();
- properties.load(Testext.class.getClassLoader()
- .getResourceAsStream("resources/testpro.properties"));
- System.out.println(properties.getProperty("sui"));
- }
- }
总结:很显然ClassLoader与URLClassLoader的区别是:
ClassLoader只能读位于classpath下的文件(即:resources/testpro.properties必须放到src目录下,编译后进入bin目录);
而URLClassLoader可以读任意目录下的文件!
2. 载入一个类
用ClassLoader载入一个类:
- import java.io.IOException;
- public class Testext {
- public static void main(String[] args) throws IOException,
- ClassNotFoundException {
- Class c = Testext.class.getClassLoader().loadClass("stalk.STalkClient");
- System.out.println(c.getName()); //输出:stalk.STalkClient
- }
- }
用URLClassLoader载入一个类:
- import java.io.IOException;
- import java.net.URL;
- import java.net.URLClassLoader;
- public class Testext {
- public static void main(String[] args) throws IOException,
- ClassNotFoundException {
- URL[] urls = new URL[] { new URL("file:/"
- + System.getProperty("user.dir") + "/ravageWeb/") };
- URLClassLoader ucl = new URLClassLoader(urls);
- Class c = ucl.loadClass("NoPackage");
- System.out.println(c.getName());
- }
- }
遇到的问题:"/ravageWeb/" 中第二个 / 必须写,否则报ClassNotFoundException
总结:
ClassLoader只能load位于classpath(src目录)下的类;
而URLClassLoader可以load任意目录下的类!
----------------------------------------------------------------------------------------------------------------------------------
我们知道,Java利用ClassLoader将类载入内存,并且在同一应用中,可以有很多个ClassLoader,通过委派机制,把装载的任务传递给上级的装载器的,依次类推,直到启动类装载器(没有上级类装载器)。如果启动类装载器能够装载这个类,那么它会首先装载。如果不能,则往下传递。当父类为null时,JVM内置的类(称为:bootstrap class loader)就会充当父类。想想眼下的越来越多用XML文件做配置文件或者是描述符、部署符。其实这些通过XML文档描述的配置信息最终都要变成 Java类,基实都是通过ClassLoader来完成的。URLClassLoader是ClassLoader的子类,它用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。也就是说,通过URLClassLoader就可以加载指定jar中的class到内存中。
下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加载jar并运行其中的类的某个方法。
首先我们定义一个接口,使所有继承它的类都必须实现action方法,如下:
public interface ActionInterface {
public String action();
}
完成后将其打包为testInterface.jar文件。
接下来新建一工程,为了编译通过,引入之前打好的testInterface.jar包。并创建TestAction类,使它实现 ActionInterface接口。如下:
public class TestAction implements ActionInterface {
public String action() {
return " com.mxjava.TestAction.action " ;
}
}
完成后将其打包为test.jar,放在c盘根目录下。下面要做的就是利用URLClassLoader加载并运行TestAction的action方法,并将返回的值打印在控制台上。
新建一工程,引入testInterface.jar包。并创建一可执行类(main方法),在其中加入如下代码:
URL url = new URL(“file:C: / test.jar”);
URLClassLoader myClassLoader = new URLClassLoader( new URL[] { url } );
Class myClass = myClassLoader.loadClass(“com.mxjava.TestAction”);
ActionInterface action = (ActionInterface)myClass.newInstance();
System.out.println(action.action());
在上面的例子中,首先利用URLClassLoader加载了C:/test.jar包,将其中的com.mxjava.TestAction类载入内存,将其强制转型为testInterface包中的ActionInterface类型,最后调用其action方法,并打印到控制台中。
执行程序后,在控制台上如期打印出我们想要的内容。但是,事情并没有那么简单,当我们将该代码移动web应用中时,就会抛出异常。原来,Java为我们提供了三种可选择的ClassLoader:
1. 系统类加载器或叫作应用类加载器 (system classloader or application classloader)
2. 当前类加载器
3. 当前线程类加载器
在上例中我们使用javac命令来运行该程序,这时候使用的是系统类加载器 (system classloader)。这个类加载器处理 -classpath下的类加载工作,可以通过ClassLoader.getSystemClassLoader()方法调用。 ClassLoader 下所有的 getSystemXXX()的静态方法都是通过这个方法定义的。在代码中,应该尽量少地调用这个方法,以其它的类加载器作为代理。否则代码将只能工作在简单的命令行应用中。当在web应用中时,服务器也是利用ClassLoader来加载class的,由于ClassLoader的不同,所以在强制转型时JVM认定不是同一类型。(在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例kl1加载,Cl的实例,即C1.class在JVM中表示为 (Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它们所加载的类也因此完全不同,互不兼容的。)为了能够使程序正确运行,我们首要解决的问题就是,如何将 URLClassLoader加载的类,同当前ClassLoader保持在同一类加载器中。解决方法很简单,利用java提供的第三种 ClassLoader—当前线程类加载器即可。jdk api文档就会发现,URLClassLoader提供了三种构造方式:
// 使用默认的委托父 ClassLoader 为指定的 URL 构造一个新 URLClassLoader。
URLClassLoader(URL[] urls)
// 为给定的 URL 构造新 URLClassLoader。
URLClassLoader(URL[] urls, ClassLoader parent)
// 为指定的 URL、父类加载器和 URLStreamHandlerFactory 创建新 URLClassLoader。
URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)
接下来要做的就是,在构造URLClassLoader时,将当前线程类加载器置入即可。如下:
URLClassLoader myClassLoader = new URLClassLoader( new URL[] { url } , Thread.currentThread().getContextClassLoader());
总结:
Java是利用ClassLoader来加载类到内存的,ClassLoader本身是用java语言写的,所以我们可以扩展自己的 ClassLoader。利用URLClassLoader可以加载指定jar包中的类到内存。在命行上利用URLClassLoader加载jar时,是使用系统类加载器来加载class的,所以在web环境下,就会出错。这是因为JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识的。我们只要利用URLClassLoader的第二种构造方法并传入当前线程类加载器即可解决。
相关推荐
该类加载器用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。如果不是以该字符结束,则认为该 URL 指向一个将根据需要打开的 JAR 文件pac
执行链实际为:URLClassLoader.class.getConstructor(java.net.URL[].class).newInstance(new
使用URLClassLoader加载本地文件夹c盘下的test.jar文件
NULL 博文链接:https://yklovejava-163-com.iteye.com/blog/1736631
Springboot + Hutool-db 使用 URLClassLoader 动态加载外部数据库和数据池 jar包实例
NULL 博文链接:https://shihuan830619.iteye.com/blog/2160884
at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang....
at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(NativeMethod) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at sun.misc....
at java.net.URLClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.access$100(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController....
at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang....
Spring bean 一般通过配置文件和注解进行加载,如果要实现jar或class文件,动态实现spring bean 的动态加载,并通过UrlClassLoader完成jar和class文件的加载。可以实现jar的热替换。spring的bean动态加载则需要对...
at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.load...
at java.net.URLClassLoader.findClass(URLClassLoader.java:434) at com.ibm.ws.bootstrap.ExtClassLoader.findClass(ExtClassLoader.java:204) at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:688...
3. 自定义URLClassLoader。检查实现类.class文件的修改时间,如果是更新的.class文件则重新加载该实现类的class。 4. 调用方法前,先获取最新的代理类,然后调用代理类的方法。 这样,每次调用代理类中的方法,都会...
创建 URLClassLoader 类加载器 * 2.获取当前执行的classpath的所有jar包的路径 * 3.通过java的ToolProvider创建JavaCompile,用来执行class源文件 * 4.创建DiagnosticCollector用来执行获取执行失败的错误结果 *...
at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.load...
2):网络加载:java.net.URLClassLoader可以加载url指定的类 3):从jar、zip等等压缩文件加载类,自动解析jar文件找到class文件去加载util类 4):从java源代码文件动态编译成为class文件 当一个类被加载、连接、...
华为编程规范和范例,提供一个规范代码的参考,提到代码的可阅读性.
规则 5.6 避免完全依赖URLClassLoader和java.util.jar提供的默认自动签名认证机制 规则 6.1 禁止给仅执行非特权操作的代码签名 规范 6.2 不要使用危险的许可与目标组合 规则 6.3 不要禁用字节码验证 规则 6.4 ...
目录 第1章 lambda表达式 0 1.1 为什么要使用lambda表达式 2 1.2 lambda表达式的语法 4 1.3 函数式接口 6 1.4 方法引用 8 1.5 构造器引用 10 ...9.5.5 URLClassLoader 206 9.5.6 BitSet 206 练习 207 索引 209