- 浏览: 453761 次
- 性别:
- 来自: 大连
博客专栏
-
《Spring Secur...
浏览量:384296
文章分类
最新评论
-
蒙奇君杰:
必须感谢一番!!!愿开源的态度为更多的人所拥有,所 认同!
关于对《Spring Security3》一书的翻译说明 -
601235723:
bbjavaeye 写道你好,有个问题请教一下我配了<b ...
《Spring Security3》第四章第一部分翻译下(自定义的UserDetailsService) -
bay0902:
中国互联网的脊梁
Spring Security 3全文下载 -
hdcustc:
项目源码下载 微博网盘里的那个依赖文件损坏了啊 能否提供个可 ...
Spring Security 3全文下载 -
i641878506:
楼主辛苦, 可以提供原书的原项目文件的下载么
Spring Security 3全文下载
声明:源码版本为Tomcat 6.0.35
在本系列的第二篇文章中,曾经介绍过在Tomcat启动时会初始化类加载器(ClassLoader),来处理整个Web工程中Class的加载问题。
类加载机制是Java平台中相当重要的核心技术,待笔者有所积累后会再次讨论这个话题。在一般的业务开发中我们可能较少接触和使用ClassLoader,但是在进行框架级程序开发时,设计良好的类加载机制能够实现更好地模块划分和更优的设计,如Java模块化技术OSGi就是通过为每个组件声明独立的类加载器来实现组件的动态部署功能。在Tomcat的代码实现中,为了优化内存空间以及不同应用间的类隔离,Tomcat通过内置的一些类加载器来完成了这些功能。
在Java语言中,ClassLoader是以父子关系存在的,Java本身也有一定的类加载规范。在Tomcat中基本的ClassLoader层级关系如下图所示:
在Tomcat启动的时候,会初始化图示所示的类加载器。而上面的三个类加载器:CommonClassLoader、CatalinaClassLoader和SharedClassLoader是与具体部署的Web应用无关的,而WebappClassLoader则对应Web应用,每个Web应用都会有独立的类加载器,从而实现类的隔离。
我们首先来看Tomcat的初始化,在Bootstrap的init方法中,会调用initClassLoaders方法,该方法负责前图中前三个类加载器的初始化:
private void initClassLoaders() { try { //初始化CommonClassLoader commonLoader = createClassLoader("common", null); if( commonLoader == null ) { 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); } }
我们可以看到,此书初始化了三个类加载器,并且catalinaLoader和sharedLoader都以commonLoader作为父类加载器,在这个方法中,将核心的业务交给了createClassLoader方法来实现:
private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception { //读取配置属性,相关的配置属性在catalina.properties文件中 String value = CatalinaProperties.getProperty(name + ".loader"); //如果没有对应的配置,将不会创建新的类加载器,而是返回传入的父类加载器 if ((value == null) || (value.equals(""))) return parent; //解析得到的配置文件,确定本ClassLoader要加载那些目录下的资源和JAR包等 StringTokenizer tokenizer = new StringTokenizer(value, ","); while (tokenizer.hasMoreElements()) { String repository = tokenizer.nextToken(); //此处省略的代码为将配置文件中的${catalina.base}、${catalina.home}等变量转 //换为绝对路径 //格式化得到的位置路径和类型 String[] locations = (String[]) repositoryLocations.toArray(new String[0]); Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]); //生成真正的类加载器 ClassLoader classLoader = ClassLoaderFactory.createClassLoader (locations, types, parent); //以下的代码为将生成的类加载器注册为MBean return classLoader; }
而每个类加载器所加载的路径或JAR是在catalina.properties文件中定义的,默认的配置如下:
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar server.loader= shared.loader=
按照默认的配置,catalinaLoader和sharedLoader的配置项为空,因此不会创建对应的ClassLoader,而只会创建CommonClassLoader,该类加载器对应的Java实现类为:org.apache.catalina.loader. StandardClassLoader,该类继承自org.apache.catalina.loader. URLClassLoader,有关Tomcat基础类都会有该类加载器加载。例如在Bootstrap的init方法中,会调用Catalina类的init方法来完成相关操作:
public void init() throws Exception{ //将当前线程的类加载器设置为catalinaLoader Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); //使用catalinaLoader来加载Catalina类 Class startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); //调用Catalina的setParentClassLoader方法,设置为sharedLoader 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; }
以上为基础的三个类加载器的初始化过程。在每个Web应用初始化的时候,StandardContext对象代表每个Web应用,它会使用WebappLoader类来加载Web应用,而WebappLoader中会初始化org.apache.catalina.loader. WebappClassLoader来为每个Web应用创建单独的类加载器,在上一篇文章中,我们介绍过,当处理请求时,容器会根据请求的地址解析出由哪个Web应用来进行对应的处理,进而将当前线程的类加载器设置为请求Web应用的类加载器。让我们看一下WebappClassLoader的核心方法,也就是loadClass:
public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz = null; //首先检查已加载的类 // (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 J2SE classes try { clazz = system.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); //Tomcat允许按照配置来确定优先使用本Web应用的类加载器加载还是使用父类 //加载器来进行类加载,此处先使用父类加载器进行加载 // (1) Delegate to our parent if requested if (delegateLoad) { if (log.isDebugEnabled()) log.debug(" Delegating to parent classloader1 " + parent); ClassLoader loader = parent; if (loader == null) loader = system; try { clazz = loader.loadClass(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { ; } } //使用本地的类加载器进行加载 // (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) { ; } //如果没有特殊配置的话,使用父类加载器加载类 // (3) Delegate to parent unconditionally if (!delegateLoad) { if (log.isDebugEnabled()) log.debug(" Delegating to parent classloader at end: " + parent); ClassLoader loader = parent; if (loader == null) loader = system; try { clazz = loader.loadClass(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { ; } } //若最终类还是没有找到,抛出异常 throw new ClassNotFoundException(name); }以上就是Web应用中类加载的机制。在默认情况下,WebappClassLoader的父类加载器就是CommonClassLoader,但是我们可以通过修改catalina.properties文件来设置SharedClassLoader,从而实现多个Web应用共用类库的效果。
评论
好主意,我也是觉得对ClassLoader这样一个复杂的概念,一篇短短的文章难以讲透,看国庆期间是不是有空,到时候再写一篇
发表评论
-
《Spring In Action》第三版译序
2013-07-12 12:19 3061《Spring In Action》第三 ... -
Tomcat源码解读系列(三)——Tomcat对HTTP请求处理的整体流程
2012-09-09 22:34 6951声明:源码版本为Tomcat 6.0.35 前面的文章 ... -
Tomcat源码解读系列(二)——Tomcat的核心组成和启动过程
2012-09-02 16:59 6372声明:源码版本为Tom ... -
Tomcat源码解读系列(一)——server.xml文件的配置
2012-08-25 07:31 6471Tomcat是JEE开发人员最常用到的开发工具,在Jav ... -
《Spring Security3》附录翻译(参考资料)
2012-02-13 22:58 6568附录:参考材料 在本附录中, ... -
《Spring Security3》第十三章翻译(迁移到Spring Security 3)
2012-02-13 22:50 5359第十三章 迁移到Spring Security 3 ... -
《Spring Security3》第十二章翻译(Spring Security扩展)
2012-02-13 22:38 8010第十二章 Spring Security扩展 ... -
《Spring Security3》第十一章(客户端证书认证)第二部分翻译
2012-02-13 22:23 4960在Spring Security中配置客户端证书认证 ... -
《Spring Security3》第十一章(客户端证书认证)第一部分翻译
2012-02-13 22:00 6216第十一章 客户端证书认证(Client Cert ... -
《Spring Security3》第十章(CAS)第二部分翻译(CAS高级配置)
2012-01-19 13:07 8631高级CAS配置 ... -
《Spring Security3》第十章(CAS)第一部分翻译(CAS基本配置)
2012-01-19 12:54 12350第十章 使用中心认证服务(CAS)进行单点登录 ... -
《Spring Security3》第九章(LDAP)第三部分翻译(LDAP明确配置)
2012-01-19 12:44 6455明确的LDAP bean配置 ... -
《Spring Security3》第九章(LDAP)第二部分翻译(LDAP高级配置)
2012-01-19 12:36 7209LDAP的高级配置 一旦我们 ... -
《Spring Security3》第九章(LDAP)第一部分翻译(LDAP基本配置)
2012-01-19 12:22 6182第九章 LDAP目录服务 在本章中,我们 ... -
《Spring Security3》第八章第三部分翻译(属性交换)
2012-01-18 15:46 2953属性交换(Attribute Exchange) ... -
《Spring Security3》第八章第二部分翻译(OpenID用户的注册)
2012-01-18 13:39 5415OpenID用户的注册问 ... -
《Spring Security3》第八章第一部分翻译(OpenID与Spring Security)
2012-01-17 22:38 7565第八章 对OpenID开放 OpenID是 ... -
《Spring Security3》第七章第三部分翻译(ACL的注意事项)
2012-01-17 22:25 2705典型ACL部署所要考虑的事情 ... -
《Spring Security3》第七章第二部分翻译(高级ACL)(下)
2012-01-17 22:17 4207支持ACL的Spring表达式语言 SpEL对A ... -
《Spring Security3》第七章第二部分翻译(高级ACL)(上)
2012-01-10 22:59 4681高级ACL话题 一些高级的话 ...
相关推荐
《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于理解和优化应用性能至关重要。本文将深入探讨Tomcat的ClassLoader是如何工作的,以及它如何影响到...
【标题】"Tomcat源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...
源码解析部分则是对Tomcat源码的深度剖析,涵盖了关键类和方法的作用、设计模式的运用以及性能优化技巧。这有助于开发者理解Tomcat内部的工作流程,例如,如何处理HTTP请求的生命周期,以及线程池是如何调度和管理的...
本篇将聚焦于"Tomcat源码阅读(一)——环境搭建",探讨如何搭建一个适合源码学习的开发环境。 首先,我们需要了解Tomcat是什么。Tomcat是一款开源的Java Servlet容器,由Apache软件基金会维护,实现了Java EE中的...
Tomcat源码剖析 : 整体架构 层层分析 源码解析 架构分析 (Http服务器功能:Socket通信(TCP/IP)、解析Http报文 Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑...
前言从今天开始,我们开始分析tomcat的源码,至于原因嘛,第一Tomcat是非常优秀的web服务器,它占据着全球一半以上的市场份额,就连spring boot
tomcat工作原理深入详解——HowTomcatWorks中文版.pdf
在IT行业中,Ant和Tomcat是两个非常关键的组件,分别用于...通过Ant编译源码,MyEclipse导入和运行,开发者可以更深入地理解Tomcat的工作机制,并进行定制化开发。在实践中不断探索,将有助于提升你的Java EE开发技能。
Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...
### tomcat源码解析 #### 简介与概览 Tomcat作为一款开源的Servlet容器,被广泛应用于Java Web应用的开发与部署环境中。它不仅支持Servlet API,还支持JSP规范,使得开发者能够轻松地构建动态网页。本文旨在深入...
Tomcat使用自定义的类加载器来加载Web应用中的类,以实现不同应用之间的类隔离。主要有CommonClassLoader、SharedClassLoader和WebappClassLoader,它们按层次加载类。 5. **连接器(Connector)与协议处理器...
Tomcat作为一款广泛使用的开源Java Servlet容器,其源码解读对于理解其工作原理至关重要。在深入源码之前,我们需要了解Tomcat的基本架构和关键组件。Tomcat的顶层由Server和Service两个核心组件构成。 **Server...
【标题】"Tomcat源码导入MyEclipse"是一个针对Java开发者的重要实践操作,它涉及到两个关键组件:Tomcat服务器和MyEclipse集成开发环境。Tomcat是Apache软件基金会的一个开源项目,它作为Servlet和JavaServer Pages...
本文将深入探讨“编译Tomcat源码所需jar包”这一主题,帮助开发者了解如何从源码构建Tomcat,以及在这个过程中需要用到的关键jar包。 首先,我们来了解一下为什么要从源码编译Tomcat。直接下载预编译的二进制版本...
3. **Servlet生命周期**:Servlet在Tomcat中的生命周期包括加载、初始化、服务、销毁四个阶段。Tomcat通过Servlet容器管理Servlet实例,确保其正确地创建、初始化和销毁。 4. **请求处理**:当一个HTTP请求到达时,...
文件描述: 1.tomcat源码文件 2.tomcat程序文件 3.Ant程序文件 4.tomcat源码在eclipse运行,重新编译,重新打包步骤文件 ...1.用于学习tomcat源码和了解tomcat运行机制 2.学习如何修改tomcat源码后如何重新编译,打包。
源码分析是提升开发者对服务器内部运作机制理解的重要途径,尤其对于Tomcat这样的核心组件,源码的学习能够帮助我们更深入地理解Web应用的部署、运行以及性能优化。 首先,我们要了解Tomcat的架构。Tomcat7基于...