public class DyLoader extends ClassLoader { public DyLoader() { super(DyLoader.class.getClassLoader()); }
public Class loadFromCustomRepository(String className) { /**取環(huán)境變量*/ String classPath = System.getProperty("java.class.path"); List classRepository = new ArrayList(); /**取得該路徑下的所有文件夾 */ if ( (classPath != null) && ! (classPath.equals(""))) { StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); while (tokenizer.hasMoreTokens()) { classRepository.add(tokenizer.nextToken()); } } Iterator dirs = classRepository.iterator(); byte[] classBytes = null; /**在類路徑上查找該名稱的類是否存在,如果不存在繼續(xù)查找*/ while (dirs.hasNext()) { String dir = (String) dirs.next(); //replace '.' in the class name with File.separatorChar & append .class to the name String classFileName = className.replace('.', File.separatorChar); classFileName += ".class"; try { File file = new File(dir + File.separatorChar + classFileName); if (file.exists()) { InputStream is = new FileInputStream(file); /**把文件讀到字節(jié)文件*/ classBytes = new byte[is.available()]; is.read(classBytes); break; } } catch (IOException ex) { System.out.println("IOException raised while reading class file data"); ex.printStackTrace(); return null; } } return this.defineClass(className, classBytes, 0, classBytes.length);//加載類 }
}
如下調(diào)用 DyLoader loader = new DyLoader(); Class a = loader.loadFromCustomRepository("com.lijz.SampleDyService"); Class b = loader.loadFromCustomRepository("com.lijz.SampleDyService"); 第三行代碼將會(huì)拋出 java.lang.LinkageError: duplicate class definition: com/lijz/SampleDyService
如果如下調(diào)用,則一切正常,這是因?yàn)槟闶褂眯碌腃lassLoader實(shí)例來裝載com.lijz.SampleDyService" DyLoader loader= new DyLoader(); Class a loader.loadFromCustomRepository("com.lijz.SampleDyService"); DyLoader newLoader = new DyLoader(); Class b = newLoader.loadFromCustomRepository("com.lijz.SampleDyService");
public class Main() { private IDyService service = null; public Main() throws Exception { DyLoader loader = new DyLoader(); service = (IDyService) loader.loadFromCustomRepository( "com.gctech.service.test.dyloader.SampleDyService").newInstance(); service.start();
while (true) {
service.doBusiness(); Thread.sleep(1000 * 3); } }
public static void main(String[] args) throws Exception { Main main = new Main(); }
}
假設(shè)業(yè)務(wù)邏輯改變,要求SampleDyService的doBusiness打印出"hello girl"。新編譯好的SampleDyService已經(jīng)覆蓋了原來的類。在不啟動(dòng)應(yīng)用程序前提條件下如何更新新的業(yè)務(wù)邏輯呢? 分倆部來完成 第一步,在Main類里添加notifyReLoad方法,用新的classloader重新生成SampleDyService實(shí)例 public void notifyReLoad() throws Exception { service.close(); DyLoader loader = new DyLoader(); service = (IDyService) loader.loadFromCustomRepository( "com.gctech.service.test.dyloader.SampleDyService").newInstance(); service.start();
}
第二步:使用某種機(jī)制檢測(cè)來檢測(cè)SampleDyService.class已經(jīng)改變,如可以通過上面的例子啟動(dòng)一個(gè)線程檢測(cè)SampleDyService.class是否被改變,如果改變則調(diào)用Main.notifyReLoad().也可以采用主動(dòng)通知方式,如web應(yīng)用中,提供這樣的界面調(diào)用。在此例子中提供一個(gè)檢測(cè)線程。 public class DyServciceChecker extends Thread { Main main = null;
public DyServciceChecker() { } public void setMain(Main main) { this.main = main;