How Tomcat works 8: Loader类

1. 概述

  (1)需要定制加载类的原因:

  • 安全性:每个context需要有自己的class loader来加载所有内部的servlet类。而不能用系统自带的system loader来加载,否则违反安全性约束
  • 重新加载:当WEB-INF/classes中的类改变时,需要重新加载

2. Java类加载器

(1)JVM每次加载java类,先创建class对象,后载入内存

(2)JVM加载类时,会先搜索core java lib,和CLASSPATH环境变量下所有文件夹

(3)JVM三个类加载器:Bootstrap class loader, extension class loader, system class loader

  • Bootstrap class loader使用native code,加载core java类,如java.lang,java.io包,搜索core lib如rt.jar, i18n.jar
  • Extension class loader: 加载标准拓展目录, 如 /jdk/jre/lib/ext
  • System class loader: 加载CLASSPATH环境变量下的jar和目录

(4)JVM使用双亲委派模型: system->extension->bootstrap。底层先被调用,然后会把加载要求先层级委派给parent。当parent无法加载,再自己加载,都找不到则throw ClassNotFoundException

(5)Tomcat定制化的类加载器的作用:

    a. 制定特殊的加载类

    b. 缓存已经加载的类

    c. 预加载已经准备好使用的类

3. Loader接口

(1)servlet只能由访问WEB-INF/lib目录的权限

(2)Tomcat loader是一个web application loader而不是类加载

(3)定义了仓库集合:一个web应用的WEB-INF/classes和WEB-INF/lib

(4)loader通常绑定给Context,因为需要reload,所以接口有modify方法(完成return true,通过context.reload方法进行调用), 允许重新加载在context配置文件中配置<Context … reloadable="true"/>

(5)loader的实现类也可以设置是否委派给parent class loader

代码:

		package com.cisco.tomcat.loader;
		
		import java.beans.PropertyChangeListener;
		
		import com.cisco.tomcat.lifecycle.Container;
		
		public interface Loader {
			public ClassLoader getClassLoader();
			public Container getContainer();
			public void setContainer(Container container);
			public DefaultContext getDefaultContext();
			public void setDefaultContext(DefaultContext defaultContext);
			public String getInfo();
			
			/**
			 * Reload Servlet class
			 * @return
			 */
			public boolean modified();
			public boolean getDelegate();
			public void setDelegate(boolean delegate);
			public boolean getReloadable();
			public void setReloadable();
			public void addRepository(String repository);
			public String[] findRepositories();
			public void removeRepository(String repository);
			public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener);
			public PropertyChangeListener getPropertyChangeListener();
			
		}

(6)类加载UML结构图:

4. Reloader接口:

		package com.cisco.tomcat.loader;
		
		public interface Reloader {
			public void addRepository(String repository);
			public String[] findRepositories();
			public boolean modified();
		}

(1)start方法会做五个动作:

创建一个class loader->设置repository->设置class path->设置permission->启动auto-load线程

(2)创建一个类加载器

			public class WebappLoader implements Loader{
			
				private String loaderClass;
				private ClassLoader parentClassLoader = null;
				
				private WebappClassLoader createClassLoader() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
					Class<?> clazz = Class.forName(loaderClass);
					WebappClassLoader classLoader = null;
					if(parentClassLoader == null) {
						classLoader = (WebappClassLoader)clazz.newInstance();
					}else {
						Class<?>[] argType = {ClassLoader.class};
						Object[] args = {parentClassLoader};
						Constructor<?> constructor = clazz.getConstructor(argType);
						classLoader = (WebappClassLoader)constructor.newInstance(args);
					}
					return classLoader;
				}
			}

(3)设置repository:

/WEB-INF/classes传给loader.addRepository(), /WEB-INF/lib传给classloader.setJarPath()

(4)设置class path:

setClassPath,Jasper JSP compiler会使用这部分数据

(5)设置permission会把如/WEB-INF/classes和/WEB-INF/lib的权限给classloader,若未设置,立即返回

(6)为Auto-reload启动新线程

			@Override
			public void run() {
				while(!threadDone) {
					// 等待检查间隔时间
					threadSleep();
					if(!started) {
						break;
					}
					// 未结束继续
					if(!classLoader.modified()) {
						continue;
					}
					// reload结束则通知context
					notifyContext();
					break;
				}
			}
			
			
			private void threadSleep() {}
			private void notifyContext() {
				WebappContextNotifier notifier = new WebappContextNotifier();
				(new Thread(notifier)).start();
			}
			
			protected class WebappContextNotifier implements Runnable{
		
				@Override
				public void run() {
					// TODO Auto-generated method stub
					((Context) container).reload();
				}
				
			}

6. WebappClassLoader:

(1)缓存:使用ResourceEntry来代表先前加载过的class,使用HashMap<ResourceEntry>来缓存加载后的class资源

			package com.cisco.tomcat.loader;
			
			import java.net.URL;
			import java.security.cert.Certificate;
			import java.util.jar.Manifest;
			
			public class ResourceEntry {
				public long lastModified = -1;
				// 资源的二进制内容 
				public byte[] binaryContent = null;
				public Class<?> loadedClass = null;
				// 资源的加载url地址
				public URL source = null;
				public URL CodeBase = null;
				public Manifest manifest = null;
				public Certificate[] certificates = null;
			}

(2)加载类的过程

WebappClassLoader使用以下规则:

    a. 所有先前使用的类都缓存在本地缓存,所以先查询本地缓存

    b. 如果本地缓存没查询到,检查内存(ClassLoader.findLoadedClass)

    c. 如果两种内存都未查到,使用system's class loader来阻止覆盖J2EE类

    d. 如果使用了SecurityManager,如果这个类不允许使用,抛ClassNotFoundException

    e. 如果delegate = on或者这个类属于package trigger,使用parent classloader加载,如果parentclassloader=null使用system class loader

    f. 从当前repository加载类

    g. 若不再当前repository, 则委派给parent class loader若无则委派给systemclasssloader

    h. 若仍找不到,抛ClassNotFoundException

7. Bootstrap启动:

Connector.start()->context.start(),在context.start()中会调用loader.start()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值