您好,登錄后才能下訂單哦!
這篇文章主要介紹“tomcat類加載機制是什么”,在日常操作中,相信很多人在tomcat類加載機制是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”tomcat類加載機制是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
tomcat類加載器的集成體系,包含兩部分:
1.上半部分是jdk自帶的,包含:啟動類加載器,擴展類加載器,應用類加載器,這里不展開講解。如果想了解,可以查看sun.misc.Launcher.Launcher()和java.lang.ClassLoader.loadClass(String, boolean)源碼
2.下半部分是tomcat的自定義類加載器,包含:
a)commonClassLoader:通過${tomcatpath}/conf/catalina.properties中的common.loader配置,通常加載tomcat和webapp共享的class
b) catalinaClassLoader: 通過${tomcatpath}/conf/catalina.properties中的server.loader配置,加載tomcat需要的class,對webapp不可見
c) sharedClassLoader:通過${tomcatpath}/conf/catalina.properties中的shared.loader配置, 加載webapp們共享的class,對tomcat容器不可見
d) webappClassLoader: 這個類加載器,就是加載我們寫的應用程序class的。通常說的tomcat打破雙親委派就是說的它
1.初始化自定義加載器
// org.apache.catalina.startup.Bootstrap.initClassLoaders() private void initClassLoaders() { try { commonLoader = createClassLoader("common", null); if (commonLoader == null) { // no config file, default to this loader - we might be in a 'single' env. commonLoader = this.getClass().getClassLoader(); } catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } }
2.初始化webappclassloader
org.apache.catalina.loader.WebappLoader.startInternal() protected void startInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug(sm.getString("webappLoader.starting")); if (context.getResources() == null) { log.info("No resources for " + context); setState(LifecycleState.STARTING); return; } // Construct a class loader based on our current repositories list try { // 創建classloader,并將父classloader設置成sharedClassLoader classLoader = createClassLoader(); classLoader.setResources(context.getResources()); // 設置委派模式 classLoader.setDelegate(this.delegate); // Configure our repositories setClassPath(); setPermissions(); // 開始類加載 ((Lifecycle) classLoader).start(); String contextName = context.getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } ObjectName cloname = new ObjectName(context.getDomain() + ":type=" + classLoader.getClass().getSimpleName() + ",host=" + context.getParent().getName() + ",context=" + contextName); Registry.getRegistry(null, null) .registerComponent(classLoader, cloname, null); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.error( "LifecycleException ", t ); throw new LifecycleException("start: ", t); } setState(LifecycleState.STARTING); } private WebappClassLoaderBase createClassLoader() throws Exception { Class<?> clazz = Class.forName(loaderClass); WebappClassLoaderBase classLoader = null; if (parentClassLoader == null) { parentClassLoader = context.getParentClassLoader(); } else { context.setParentClassLoader(parentClassLoader); } Class<?>[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor<?> constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoaderBase) constr.newInstance(args); return classLoader; }
3.裝配應用class文件
// org.apache.catalina.loader.WebappClassLoaderBase.start() public void start() throws LifecycleException { state = LifecycleState.STARTING_PREP; // 掃描 /WEB-INF/classes 下的class WebResource[] classesResources = resources.getResources("/WEB-INF/classes"); for (WebResource classes : classesResources) { if (classes.isDirectory() && classes.canRead()) { localRepositories.add(classes.getURL()); } } // 掃描 /WEB-INF/lib 下的jar WebResource[] jars = resources.listResources("/WEB-INF/lib"); for (WebResource jar : jars) { if (jar.getName().endsWith(".jar") && jar.isFile() && jar.canRead()) { localRepositories.add(jar.getURL()); // 記錄jar的修改時間,用于熱更新 jarModificationTimes.put( jar.getName(), Long.valueOf(jar.getLastModified())); } } state = LifecycleState.STARTED; }
4.tomcat熱更新:
// org.apache.catalina.loader.WebappLoader.backgroundProcess() public void backgroundProcess() { // reloadable:是否開啟熱更新 // modified():判斷jar和class是否有修改(這里會導致cpu瞬間高) if (reloadable && modified()) { try { Thread.currentThread().setContextClassLoader (WebappLoader.class.getClassLoader()); if (context != null) { context.reload(); } } finally { if (context != null && context.getLoader() != null) { Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); } } } }
5.加載一個class文件的過程:
// org.apache.catalina.loader.WebappClassLoaderBase.loadClass(String) public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { Class<?> clazz = null; // Log access to stopped class loader checkStateForClassLoading(name); // (0) Check our previously loaded local class cache // 從本地緩存查找 clazz = findLoadedClass0(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Returning class from cache"); if (resolve) resolveClass(clazz); return clazz; } // (0.1) Check our previously loaded class cache // 從父類類加載器緩存查找 clazz = findLoadedClass(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Returning class from cache"); if (resolve) resolveClass(clazz); return clazz; } // (0.2) Try loading the class with the system class loader, to prevent // the webapp from overriding Java SE classes. This implements // SRV.10.7.2 String resourceName = binaryNameToPath(name, false); ClassLoader javaseLoader = getJavaseClassLoader(); boolean tryLoadingFromJavaseLoader; try { // Use getResource as it won't trigger an expensive // ClassNotFoundException if the resource is not available from // the Java SE class loader. However (see // https://bz.apache.org/bugzilla/show_bug.cgi?id=58125 for // details) when running under a security manager in rare cases // this call may trigger a ClassCircularityError. // See https://bz.apache.org/bugzilla/show_bug.cgi?id=61424 for // details of how this may trigger a StackOverflowError // Given these reported errors, catch Throwable to ensure any // other edge cases are also caught URL url; if (securityManager != null) { PrivilegedAction<URL> dp = new PrivilegedJavaseGetResource(resourceName); url = AccessController.doPrivileged(dp); } else { url = javaseLoader.getResource(resourceName); } tryLoadingFromJavaseLoader = (url != null); } catch (Throwable t) { // Swallow all exceptions apart from those that must be re-thrown ExceptionUtils.handleThrowable(t); // The getResource() trick won't work for this class. We have to // try loading it directly and accept that we might get a // ClassNotFoundException. tryLoadingFromJavaseLoader = true; } // 嘗試用加載String類(即啟動類加載器)的類加載器加載 if (tryLoadingFromJavaseLoader) { try { clazz = javaseLoader.loadClass(name); if (clazz != null) { if (resolve) resolveClass(clazz); return clazz; } } catch (ClassNotFoundException e) { // Ignore } } // (0.5) Permission to access this class when using a SecurityManager if (securityManager != null) { int i = name.lastIndexOf('.'); if (i >= 0) { try { securityManager.checkPackageAccess(name.substring(0,i)); } catch (SecurityException se) { String error = "Security Violation, attempt to use " + "Restricted Class: " + name; log.info(error, se); throw new ClassNotFoundException(error, se); } } } // 判斷是否委派給父類加載器 boolean delegateLoad = delegate || filter(name, true); // (1) Delegate to our parent if requested // 委派給父類加載器(sharedClassLoader),符合委派雙親 if (delegateLoad) { if (log.isDebugEnabled()) log.debug(" Delegating to parent classloader1 " + parent); try { clazz = Class.forName(name, false, parent); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return clazz; } } catch (ClassNotFoundException e) { // Ignore } } // (2) Search local repositories // 在本地存儲庫查找并加載 if (log.isDebugEnabled()) log.debug(" Searching local repositories"); try { clazz = findClass(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Loading class from local repository"); if (resolve) resolveClass(clazz); return clazz; } } catch (ClassNotFoundException e) { // Ignore } // (3) Delegate to parent unconditionally // 即使沒有委派,最后也執行一次委派 if (!delegateLoad) { if (log.isDebugEnabled()) log.debug(" Delegating to parent classloader at end: " + parent); try { clazz = Class.forName(name, false, parent); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return clazz; } } catch (ClassNotFoundException e) { // Ignore } } } throw new ClassNotFoundException(name); }
到此,關于“tomcat類加載機制是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。