今天在修改項目一個JSP文件時,突然想到Tomat是怎么實現動態實時加載JSP編譯后的class類的?
查了半天資料,看了很多文章,終于明白是怎么回事了:ClassLoader,當tomcat發現jsp改變后,將用新的ClassLoader去加載新的類
具體原理我將單獨總結一下,這里簡單實現了動態加載類
1.定義服務類
public class Servlet { public void service(){ System.out.println( "運行服務方法" ); } }
2.定義服務線程
public class ServiceThread extends Thread{ public void run(){ try { ClassLoader classLoader = this .getContextClassLoader(); Class clazz = classLoader.loadClass("Servlet" ); Method service = clazz.getMethod("service", null ); service.invoke(clazz.newInstance(), null ); } catch (Exception e) { e.printStackTrace(); } } }
?
3.自定義ClassLoader
public class MyClassLoader extends ClassLoader{ @Override public Class loadClass(String name, boolean resolve) throws ClassNotFoundException{ try { // 我們要創建的Class對象 Class clasz = null ; // 必需的步驟1:如果類已經在系統緩沖之中 // 我們不必再次裝入它 clasz = findLoadedClass(name); if (clasz != null ) return clasz; try { // 讀取經過加密的類文件 if (name.equals("Servlet" )){
//加載class文件字節 byte classData[] = Util.readFile(ProgramPathHelper.getProgramPath()+"/"+name + ".class" ); if (classData != null ) { // ... 再把它轉換成一個類 clasz = defineClass(name, classData, 0 , classData.length); } } } catch (Exception e) { e.printStackTrace(); } // 必需的步驟2:如果上面沒有成功 // 我們嘗試用默認的ClassLoader裝入它 if (clasz == null ) clasz = findSystemClass(name); // 必需的步驟3:如有必要,則裝入相關的類 if (resolve && clasz != null ) resolveClass(clasz); // 把類返回給調用者 return clasz; } catch (Exception ie) { throw new ClassNotFoundException(ie.toString()); } } }
?
4.實現文件監聽類
public class CCFileListener implements FileAlterationListener{ public static HashMap<String,ClassLoader> claMap = new HashMap<String, ClassLoader> (); ZJPFileMonitor monitor = null ; @Override public void onStart(FileAlterationObserver observer) { // System.out.println("onStart"); } @Override public void onDirectoryCreate(File directory) { System.out.println( "onDirectoryCreate:" + directory.getName()); } @Override public void onDirectoryChange(File directory) { System.out.println( "onDirectoryChange:" + directory.getName()); } @Override public void onDirectoryDelete(File directory) { System.out.println( "onDirectoryDelete:" + directory.getName()); } @Override public void onFileCreate(File file) { System.out.println( "onFileCreate:" + file.getName()); dyncLoadClass(file.getName()); } @Override public void onFileChange(File file) {
//文件改變處理函數 System.out.println( "onFileChange : " + file.getName()); dyncLoadClass(file.getName()); } private void dyncLoadClass(String className){ if (className.contains("Servlet" )){ // ZJPFileMonitor.thread.setContextClassLoader(new MyClassLoader()); claMap.put(className, new MyClassLoader()); } } @Override public void onFileDelete(File file) { System.out.println( "onFileDelete :" + file.getName()); } @Override public void onStop(FileAlterationObserver observer) { // System.out.println("onStop"); } }
public class CCFileMonitor { FileAlterationMonitor monitor = null ; public CCFileMonitor( long interval) throws Exception { monitor = new FileAlterationMonitor(interval); } public void monitor(String path, FileAlterationListener listener) { FileAlterationObserver observer = new FileAlterationObserver( new File(path)); monitor.addObserver(observer); observer.addListener(listener); } public void stop() throws Exception{ monitor.stop(); } public void start() throws Exception { monitor.start(); } public static void main(String[] args) throws Exception { CCFileMonitor m = new CCFileMonitor(5000 ); m.monitor(ProgramPathHelper.getProgramPath(), new CCFileListener()); m.start(); Servlet servlet = new Servlet(); servlet.service(); MyClassLoader defaultCl = new MyClassLoader(); while ( true ){ Thread.currentThread().sleep( 3000 ); Thread t = new ServiceThread(); //設置新線程的類加載器 ClassLoader classLoader = CCFileListener.claMap.get("Servlet.class" ); if (classLoader== null ){ classLoader = defaultCl; } t.setContextClassLoader(classLoader); t.start(); } } }
public static HashMap<String,ClassLoader> claMap = new HashMap<String, ClassLoader>
();
在監聽到文件改變后,依據類名重new一個類加載器,用于加載類。
ClassLoader classLoader = CCFileListener.claMap.get("Servlet.class"
);
if(classLoader==null
){
classLoader =
defaultCl; }
首先獲取類名對應的加載器,如果沒有使用默認的加載器
ClassLoader classLoader = this
.getContextClassLoader(); Class clazz = classLoader.loadClass("Servlet"
); Method service = clazz.getMethod("service", null
); service.invoke(clazz.newInstance(), null
);
在線程內部使用剛才在外部設置的線程上下文加載器加載新的Servlet,并執行
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
