摘要:加载器之间父子关系不是通过类继承的方式,而是通过对象变量的方式,来实现的。调用的方法,将设置为所有的获取各个类加载器相应的资源配置文件这些是具体配置在配置文件中的。
摘要
一直以来想看一下tomcat的源码,可以从头到尾理解一遍在整个web请求的处理过程中,容器完成的功能,容器怎么把一个url的请求的处理递交给了servlet,容器的pipeline是怎么设计的,容器的filter怎么实现的,如何维护session,好多好多的问题,有幸发现一篇文章Tomcat7.0源码分析,让我得以窥见容器的内部实现,从源码之中能按着作者的思路来理解和阅读。读完之后,有了一些理解,但是不是很深刻,借着这个机会,写了这篇总结,温故而知新。读源代码,就是要反复得读,每次读完都会先释然,又会产生新的疑惑,再带着问题重读源码,如此反复,脉络才会越来越清晰。
整个文章按如下几个主题:
tomcat的类加载体系
server.xml文件的加载与解析
生命周期管理
停止与启动服务
请求原理分析
session管理分析
TOMCAT的类加载体系Tomcat为了webapp之间以及app和容器之间的资源(jar包)隔离,是通过自定义类加载器的方式来实现的。首先我们看一下jdk的类加载器结构树(为了方便起见,将tomcat自定义的类加载器也放上去了)
这个粗看会有一点困惑,jdk不是父亲委派加载机制吗?为什么这里的AppClassLoader,ExtClassLoad不是继承关系呢?其实这是一个误解。加载器之间父子关系不是通过类继承的方式,而是通过对象变量的方式,来实现的。
private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent;
然后在加载类的时候,会尝试先让parent来加载
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); }
这个就是父亲委托加载机制的由来。之前找不到JDK的ExtClassLoader和AppClassLoader,后来才发现这两个类原来是rt.jar包sum.msic.Launcher的内部类. Bootstrap加载sum.boot.class.path下的类,ExtClassPath加载java.ext.dirs下的类,AppClassLoader加载java.class.path下的类。当然也可以在运行时通过参数( -XBootclasspath , -Djava.ext.dirs , -cp)分别指定。
好了,现在让我们回到tomcat的类加载器上来,看类树上,tomcat自定义了WebappClassLoader和standardClassLoader,简单的看,前者是给web应用用的,后者是给tomcat容器本身用的。我们通过原来来进行分析。
Bootstrap.java public void init() throws Exception { // Set Catalina path setCatalinaHome(); setCatalinaBase(); initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); //调用Catalina的setParentClassLoader方法,将sharedLoader设置为所有WebappClassLoader的parent Class> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class> paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; } 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) { log.error("Class loader creation threw exception", t); System.exit(1); } } private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception { //获取各个类加载器相应的资源配置文件(common.loader,server.loader,shared.loader) //这些是具体配置在catalina.properties配置文件中的。以本机配置为例 //common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar //server.loader= //shared.loader= String value = CatalinaProperties.getProperty(name + ".loader"); if ((value == null) || (value.equals(""))) return parent; ArrayListrepositoryLocations = new ArrayList (); ArrayList repositoryTypes = new ArrayList (); int i; StringTokenizer tokenizer = new StringTokenizer(value, ","); while (tokenizer.hasMoreElements()) { String repository = tokenizer.nextToken(); // Local repository boolean replace = false; String before = repository; while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) { replace=true; if (i>0) { repository = repository.substring(0,i) + getCatalinaHome() + repository.substring(i+CATALINA_HOME_TOKEN.length()); } else { repository = getCatalinaHome() + repository.substring(CATALINA_HOME_TOKEN.length()); } } while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) { replace=true; if (i>0) { repository = repository.substring(0,i) + getCatalinaBase() + repository.substring(i+CATALINA_BASE_TOKEN.length()); } else { repository = getCatalinaBase() + repository.substring(CATALINA_BASE_TOKEN.length()); } } if (replace && log.isDebugEnabled()) log.debug("Expanded " + before + " to " + repository); // Check for a JAR URL repository try { new URL(repository); repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_URL); continue; } catch (MalformedURLException e) { // Ignore } if (repository.endsWith("*.jar")) { repository = repository.substring (0, repository.length() - "*.jar".length()); repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_GLOB); } else if (repository.endsWith(".jar")) { repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_JAR); } else { repositoryLocations.add(repository); repositoryTypes.add(ClassLoaderFactory.IS_DIR); } } String[] locations = repositoryLocations.toArray(new String[0]); Integer[] types = repositoryTypes.toArray(new Integer[0]); //创建ClassLoader ClassLoader classLoader = ClassLoaderFactory.createClassLoader (locations, types, parent); // Retrieving MBean server MBeanServer mBeanServer = null; if (MBeanServerFactory.findMBeanServer(null).size() > 0) { mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0); } else { mBeanServer = ManagementFactory.getPlatformMBeanServer(); } // Register the server classloader ObjectName objectName = new ObjectName("Catalina:type=ServerClassLoader,name=" + name); mBeanServer.registerMBean(classLoader, objectName); return classLoader; } //回看init方法,对应的securityClassLoad就是使用catalinaLoader完成tomcat核心类的加载的 public static void securityClassLoad(ClassLoader loader) throws Exception { if( System.getSecurityManager() == null ){ return; } loadCorePackage(loader); loadLoaderPackage(loader); loadSessionPackage(loader); loadUtilPackage(loader); loadJavaxPackage(loader); loadCoyotePackage(loader); loadTomcatPackage(loader); }
此处,完成了commonLoader,catalinaLoader和sharedLoader三个加载器的初始化,他们均是StandardClassLoader的实例,同时我们可以看到这三者之间的关系为
接下去,我们来看WebappLoader
StandardContext.java protected synchronized void startInternal() throws LifecycleException { //省略前边代码 if (getLoader() == null) { WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); webappLoader.setDelegate(getDelegate()); setLoader(webappLoader); } //省略中间代码 if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); //省略后边代码 } WebappLoader.java protected void startInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug(sm.getString("webappLoader.starting")); if (container.getResources() == null) { log.info("No resources for " + container); setState(LifecycleState.STARTING); return; } // Register a stream handler factory for the JNDI protocol URLStreamHandlerFactory streamHandlerFactory = new DirContextURLStreamHandlerFactory(); if (first) { first = false; try { URL.setURLStreamHandlerFactory(streamHandlerFactory); } catch (Exception e) { // Log and continue anyway, this is not critical log.error("Error registering jndi stream handler", e); } catch (Throwable t) { // This is likely a dual registration log.info("Dual registration of jndi stream handler: " + t.getMessage()); } } // Construct a class loader based on our current repositories list try { classLoader = createClassLoader(); classLoader.setResources(container.getResources()); classLoader.setDelegate(this.delegate); classLoader.setSearchExternalFirst(searchExternalFirst); if (container instanceof StandardContext) { classLoader.setAntiJARLocking( ((StandardContext) container).getAntiJARLocking()); classLoader.setClearReferencesStatic( ((StandardContext) container).getClearReferencesStatic()); classLoader.setClearReferencesStopThreads( ((StandardContext) container).getClearReferencesStopThreads()); classLoader.setClearReferencesStopTimerThreads( ((StandardContext) container).getClearReferencesStopTimerThreads()); classLoader.setClearReferencesThreadLocals( ((StandardContext) container).getClearReferencesThreadLocals()); } for (int i = 0; i < repositories.length; i++) { classLoader.addRepository(repositories[i]); } // Configure our repositories setRepositories(); setClassPath(); setPermissions(); ((Lifecycle) classLoader).start(); // Binding the Webapp class loader to the directory context DirContextURLStreamHandler.bind(classLoader, this.container.getResources()); StandardContext ctx=(StandardContext)container; String path = ctx.getPath(); if (path.equals("")) { path = "/"; } ObjectName cloname = new ObjectName (MBeanUtils.getDomain(ctx) + ":type=WebappClassLoader,path=" + path + ",host=" + ctx.getParent().getName()); Registry.getRegistry(null, null) .registerComponent(classLoader, cloname, null); } catch (Throwable t) { log.error( "LifecycleException ", t ); throw new LifecycleException("start: ", t); } setState(LifecycleState.STARTING); } private WebappClassLoader createClassLoader() throws Exception { Class> clazz = Class.forName(loaderClass); WebappClassLoader classLoader = null; if (parentClassLoader == null) { parentClassLoader = container.getParentClassLoader(); } Class>[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor> constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoader) constr.newInstance(args); return classLoader; }
此处完成了WebappClassLoader的初始化,可见这个类加载器是对应一个Context的,即一个web应用。其parent应该是sharedLoader.
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67795.html
摘要:一般来说会在项目中的中添加一个,里面配置这个配置文件在部署时,会被复制到中去,并被重新命名为项目名。由于使用的项目中配置了来加载第三方库,配置了我自定义加载器后,这些包都无法加载了。我往开发机上打加密补丁的时候,总是无故消失,不知道为什么 为了这个功能提了很多问题都没能得到解答,最后终于自己搞定了,现在把大体步骤总结下,供大家参考指正 分三种情况:(1)没有配置spring自动扫描(2...
时间:2017年12月01日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 热部署的使用场景 本地调式 线上发布 热部署的使用优点 无论本地还是线上,都适用 无需重启服务器:提高开发、调式效率、提升发布、运维效率、降低运维成本 前置...
阅读 892·2021-11-22 13:54
阅读 2822·2021-09-28 09:36
阅读 2958·2019-08-30 15:55
阅读 1937·2019-08-30 15:44
阅读 528·2019-08-29 12:31
阅读 2545·2019-08-28 18:18
阅读 1181·2019-08-26 13:58
阅读 1292·2019-08-26 13:44