自定义classloader主要实现的方法是 findClass(String name) , 而我们调用的则是loadClass来加载类
具体的loadClass代码请自己查阅,直接上干货:
public class NorClassLoader extends ClassLoader{
URL[] urls = null;
public NorClassLoader(){
super();
}
public NorClassLoader(URL[] urls){
this.urls = urls;
}
public NorClassLoader(URL[] urls,ClassLoader parent){
super(parent);
this.urls = urls;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> clazz = null;
if(name == null || name.length()==0)
throw new ClassNotFoundException("class <"+name+"> can't found");
try{
byte[] buffer = searchResource(name);
if(buffer == null){
throw new ClassNotFoundException("class <"+name+"> can't found");
}
clazz = defineClass(null, buffer, 0, buffer.length);
}catch(Exception e){
throw new ClassNotFoundException("class <"+name+"> can't found",e);
}
if(clazz == null){
throw new ClassNotFoundException("class <"+name+"> can't found");
}
return clazz;
}
private byte[] searchResource(String name) throws IOException{
if(urls == null || urls.length ==0){
throw new NullPointerException("urls can't be null or empty");
}
String pathName = name.replaceAll("\\.", "/");
ByteArrayOutputStream baos = null;
for(URL url : urls){
try {
File file = new File(url.toURI());
if(file.exists() && file.isDirectory()){// source folder
File clazzFile = new File(file,pathName+".class");
if(clazzFile.exists() && clazzFile.isFile()){
baos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(clazzFile);
int b = 0;
while((b=fis.read()) >=0){
baos.write(b);
}
fis.close();
break;
}
}else{
if(file.getName().endsWith(".jar")){// jar file
JarFile jarFile = new JarFile(new File(url.toURI()));
ZipEntry zentry = jarFile.getEntry(pathName+".class");
if(zentry ==null){
continue;
}else{
InputStream is = jarFile.getInputStream(zentry);
baos = new ByteArrayOutputStream();
int b = 0;
while((b=is.read())>=0){
baos.write(b);
}
is.close();
jarFile.close();
break;
}
}else if(file.getName().endsWith(".zip")){// zip file
ZipFile zipFile = new ZipFile(new File(url.toURI()));
ZipEntry zentry = zipFile.getEntry(pathName);
if(zentry ==null){
continue;
}else{
InputStream is = zipFile.getInputStream(zentry);
baos = new ByteArrayOutputStream();
int b = 0;
while((b=is.read())>=0){
baos.write(b);
}
is.close();
zipFile.close();
break;
}
}else{ // can't process the file type
continue;
}
}
} catch (URISyntaxException e) {
continue;
}
}
return baos ==null ? null : baos.toByteArray();
}
再来一个 测试用例,用例是从其他项目即时编译一个源文件用classloader加载
public class TestClassloader {
@Before
public void setUp(){
String[] args = new String[]{"-extdirs","/home/tt/workspace/java/nor/deps/",
"-sourcepath","/home/tt/workspace/java/nor/src/",
"-6","-d","/home/tt/workspace/java/nor/testbin/",
"/home/tt/workspace/java/nor/src/org/nutz/template/Start.java"};
new org.eclipse.jdt.internal.compiler.batch.Main(new PrintWriter(new ByteArrayOutputStream()),new PrintWriter(new ByteArrayOutputStream()),false,null,null).compile(args);
}
@Test
public void testNorClassloader() throws ClassNotFoundException, MalformedURLException{
ClassLoader cl = new NorClassLoader(new URL[]{new File("/home/tt/workspace/java/nor/testbin/").toURI().toURL(),
new File("/home/tt/workspace/java/nor/deps/jetty-xml-7.2.2.v20101205.jar").toURI().toURL()
},Thread.currentThread().getContextClassLoader());
Class<?> clazz = cl.loadClass("org.nutz.template.Start");
Assert.assertEquals("org.nutz.template.Start", clazz.getName());
clazz = cl.loadClass("org.eclipse.jetty.xml.XmlParser");
Assert.assertEquals("org.eclipse.jetty.xml.XmlParser", clazz.getName());
}
@After
public void tearDown(){
Files.deleteDir(new File("/home/tt/workspace/java/nor/testbin/"));
}
}
大家把 其中的变量适当替换一下,如果有class文件可以直接用classloader进行加载,