自定义Classloader 加载类---Eclipse plugin开发

17 篇文章 0 订阅
17 篇文章 0 订阅

  在我们的代码中有很多是动态加载类的,但如果使用eclipse 开发plugin会有一些问题。
  例如:要求在plugin中使用某类型的class,但由于plugin的运行环境和运行时环境不一致,导致你在进行plugin开发时遇到ClassNotFoundException等问题。在这样的情况下就要自定义ClassLoader然后,在plugin中使用。同时需要注意的一个问题是:在动态家在类的时候,最好不要使用xxx.getClass().getClassLoader()或xxx.class.getClassLoader(),因为这样一样可能导致ClassNotFountException,最好是使用Thread.currentThread().getContextClassLoader().
这样在使用自定义ClassLoader的时候,就不用修改代码,直接把自定义ClassLoader放到Thread的contextClassLoad中既可。
  ClassLoade的代码:

/*
 * Created on 2005-12-1
 */
package org.jsports.plugin.classLoader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.List;


/**
 * @author Kobye
 */
public class JsportsClassLoader extends ClassLoader {
  private String dir ;
  
  public JsportsClassLoader (ClassLoader parent,String dir){
   super(parent);
   this.dir = dir;
  } 
 
 
 protected Class findClass(String name)throws ClassNotFoundException {
  byte[] bytes = loadClassBytes(name);
  Class theClass = defineClass(name, bytes, 0, bytes.length);
  if (theClass == null){
   throw new ClassFormatError();
  }
  return theClass;
   }


 private byte[] loadClassBytes(String className) throws ClassNotFoundException {
  try {
   String classFile = getClassFile(className);
   FileInputStream fis = new FileInputStream(classFile);
   FileChannel fileC = fis.getChannel();
   ByteArrayOutputStream baos = new
   ByteArrayOutputStream();
   WritableByteChannel outC = Channels.newChannel(baos);
   ByteBuffer buffer = ByteBuffer.allocate(1024);
   while (true) {
    int i = fileC.read(buffer);
    if (i == 0 || i == -1) {
    break;
    }
    buffer.flip();
    outC.write(buffer);
    buffer.clear();
   }
   fis.close();
   return baos.toByteArray();
  } catch (IOException fnfe) {
   throw new ClassNotFoundException(className);
  }
 }


 private String getClassFile(String name){
  StringBuffer sb = new StringBuffer(dir);
  name = name.replace('.', File.separatorChar) + ".class";
  sb.append(File.separator + name);
  return sb.toString();
 }
 

 
 protected URL findResource(String name) {              
  try {                                         
   URL url = super.findResource(name);           
   if (url != null){
    return url;                                   
   }
   url = new URL("file:///" + converName(name)); 
   return url;                                  
      } catch (MalformedURLException mue) {                  
    return null;                                
   }                                           
    }      
 
 
 private String converName(String name) {     
   StringBuffer sb = new StringBuffer(dir);
   name = name.replace('.', File.separatorChar);
   sb.append(File.separator + name);           
   return sb.toString();                       
 }                                            
                                                   

 private String getClassName(String dir,File f){
  String name = f.getAbsolutePath();  
  if(name.startsWith(dir)){ 
   name = name.substring(dir.length(),name.length());
  }
  name = name.replace(File.separatorChar,'.');
  if(name.endsWith(".class")){
   name = name.substring(0,name.length()-".class".length());
  }
  return name;
 }
 private List getAllFiles(File base){
  File[]dirs = base.listFiles(new ClassFileFilter());
  File[]classFile = base.listFiles(new ClassFileNameFilter());
  List files = new ArrayList();
  for(int i=0;i<classFile.length;i++){
   files.add(classFile[i]);
  }
  for(int i=0;i<dirs.length;i++){
   files.addAll(getAllFiles(dirs[i]));
  }
  return files;
 }
 
 private File getDirByName(File dir,String dirName,String baseDir){
  if(!dir.isDirectory()){
   return null;
  }   
  String dirPath = dir.getAbsolutePath(); 
  if(dirPath.startsWith(baseDir)){
   //检查  该目下的File dir  
   dirPath = dirPath.substring(baseDir.length(),dirPath.length());
   System.out.println();
   if(dirPath.endsWith("model")){
    return dir;
   }
  }
  File[]files = dir.listFiles();
  for(int i=0;i<files.length;i++){
   File f = getDirByName(files[i],dirName,baseDir);
   if(f!=null){
    return f;
   }
  }
  return null;
 }
 
}


这个ClassLoader的功能是把dir路径下的model目录中的所有类加载。
然后这样调用:
  String path = this.getCurrentProject().getLocation().toFile().getAbsolutePath()+"//bin";
  Thread.currentThread().setContextClassLoader(new JsportsClassLoader (Thread.currentThread().getContextClassLoader(),path));  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在一个应用程序中同时加载两个版本的OJDBC驱动是比较困难的,因为Java加载器默认使用委派模型,即当一个需要被加载时,它首先会请求其父加载加载,如果父加载器无法加载,则由当前加载器尝试加载。 为了解决这个问题,我们可以使用自定义加载器来加载不同版本的OJDBC驱动。自定义加载器可以绕过默认的委派模型,从而使得我们可以在同一个应用程序中加载不同版本的。 下面是一个简单的例子,演示如何使用自定义加载加载两个版本的OJDBC驱动: ```java import java.net.URL; import java.net.URLClassLoader; public class CustomClassLoader extends URLClassLoader { public CustomClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { if (name.startsWith("oracle.jdbc.")) { String version = System.getProperty("oracle.jdbc.version"); if (version != null && version.equals("11g")) { return loadClassFromVersion(name, "11g"); } else { return loadClassFromVersion(name, "12c"); } } return super.loadClass(name); } private Class<?> loadClassFromVersion(String name, String version) throws ClassNotFoundException { String className = name.replace(".", "/") + ".class"; URL url = getResource(className.replace(version, "common")); if (url == null) { throw new ClassNotFoundException(name); } byte[] bytes = null; try { bytes = IOUtils.toByteArray(url.openStream()); } catch (IOException e) { throw new ClassNotFoundException(name, e); } return defineClass(name, bytes, 0, bytes.length); } } ``` 在这个自定义加载器中,我们重写了loadClass方法,并根据系统属性oracle.jdbc.version的值来判断应该加载哪个版本的OJDBC驱动。 如果oracle.jdbc.version的值为11g,则加载11g版本的驱动,否则加载12c版本的驱动。 在loadClass方法中,我们首先判断要加载是否以oracle.jdbc.开头,如果是,则调用loadClassFromVersion方法加载对应版本的。 在loadClassFromVersion方法中,我们首先使用getResource方法获取该对应的URL,然后读取该URL对应的字节码,并使用defineClass方法将该加载到内存中。 最后,我们在应用程序中使用自定义加载器来加载OJDBC驱动: ```java URL[] urls = new URL[] { new URL("file:///path/to/ojdbc11.jar"), new URL("file:///path/to/ojdbc12.jar") }; ClassLoader parent = ClassLoader.getSystemClassLoader(); CustomClassLoader loader = new CustomClassLoader(urls, parent); System.setProperty("oracle.jdbc.version", "11g"); // 设置oracle.jdbc.version属性为11g Class<?> driverClass = loader.loadClass("oracle.jdbc.driver.OracleDriver"); Driver driver = (Driver) driverClass.newInstance(); ``` 在这个例子中,我们首先创建一个CustomClassLoader对象,并将ojdbc11.jar和ojdbc12.jar的URL作为参数传入。 然后,我们设置oracle.jdbc.version属性为11g,并使用CustomClassLoader加载对应版本的OracleDriver,并创建该的实例。 这样,我们就可以在同一个应用程序中同时使用不同版本的OJDBC驱动了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值