java加载器就是加载class字节码或资源文件,使用自己的类加载器加载可以自定义加载任意文件目录里的类与资源文件,类被自己的类加载器加载后,在类里调用加载器(【可以看到自己是被那个加载器加载的】)加载资源classLoader.getResource,的跟目录就会变成这个类的class所在根目录,从而实现动态加载资源文件
主要有3个
Test.java main方法与自定义加载器
Handler.java 接口 ,方便加载类后,强转,调用方法
OneHandlerImpl.java 实现接口,打印加载器与加载资源文件路径,编译后的class文件测试动态加载
idea普通java项目
项目运行一次后(为了编译), 把OneHandlerImpl.class 放到其他目录(非classpath目录), 并在同级目录建立资源文件OneHandlerImpl.config,内容随便,注意看是否能够加载
由tomcat自定义加载器思考而来,可以实现自己的webapp隔离
比如配置的web.xml配置的classpath:springmvc-servlet.xml。WEB-INF下等等,扫描的包路径
URLClassLoader默认是有双亲委托的。所以刚开始在项目里运行,打印的加载器是AppClassLoader, 所以需要把编译后的OneHandlerImpl.class放到非项目的非classpath目录,测试
Test.java
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
public class Test {
public static void main(String[] args) throws Exception{
Class c = Test.loadClass("/Users/proj/testclass","OneHandlerImpl");
//使用反射调用方法
// Object obj = c.newInstance();
// Method method = c.getMethod("doIt");
// method.invoke(obj);
//通过接口强转,比反射更好
Handler handler = (Handler) c.newInstance();
handler.doIt();
}
/**
*
* @param classesPath 字节码文件目录,包的根目录,jar包文件绝对路径
* @param clazzStr 类全名,包括包名
* @return
*/
public static Class loadClass(String classesPath , String clazzStr){
try{
URL[] urls = new URL[1];
urls[0] = new URL("file",null,classesPath);
URLClassLoader loader = new URLClassLoader(urls);
return loader.loadClass(clazzStr);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
Handler.java
public interface Handler {
void doIt();
}
OneHandlerImpl.java
public class OneHandlerImpl implements Handler {
@Override
public void doIt() {
System.out.println("OneHandlerImpl");
ClassLoader classLoader = OneHandlerImpl.class.getClassLoader();
System.out.println(classLoader);
System.out.printf(classLoader.getResource("OneHandlerImpl.config").getFile());
}
}