`
ddbl7
  • 浏览: 11707 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

fried cake server ----我的油炸糕(3)远端类加载器

阅读更多
前两章主要贴出了服务器通讯核心和资源执行器的实现,这两个东西其实都不难,只要花些时间,我相信大部分的程序员都能做出来。两章结束后我们的服务器应该已经能够实现html等资源的执行了,而我们也即将遇到服务器开发中的第一个难点:远端类加载!
远端类加载是所有服务器都无法回避的第一道门槛,web服务器与web 项目是两个不同的域(或者说是两个不同的项目),app server又需要在运行中动态解析项目(包括拆war包),因此我们无法够预先定义web服务器的classPath使其支持web 项目中的类,所以远端加载势在必行。
java里面所有的类加载,都必须使用classloader,既然如此,我们就重载一个:

package util;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import server.AppRunTime;
/**
 * 这个类专门用来解析web工程里用到的class文件
 * 包括jar文件,classes文件夹,和系统类文件
 * @author 刘宇航
 */
public class LocalClassLoader extends ClassLoader {
	
	private Map<String, Class<?>> loadedClasses = new Hashtable<String, Class<?>>();
	private static Map<String,LocalClassLoader> loaders= new Hashtable<String, LocalClassLoader>();
	private String projectPath = "";
	int cacheSize=6;//默认的class文件大小
	/**
	 * 防止其他初始化途径
	 */
	private LocalClassLoader(){
		cacheSize = (Integer)AppRunTime.getInstance().getProperty(Constant.SERVER_CACHE);
	}
	/**
	 * 针对每一个工程,返回一个单例
	 * @param projPath 传入一个项目根路径 用来区分不同项目的LocalClassLoader
	 * @return LocalClassLoader
	 */
    public static LocalClassLoader getInstance(String projPath){
    	if(loaders.containsKey(projPath)==false)
    	{
    		LocalClassLoader instance  =  new LocalClassLoader();
    		instance.projectPath = projPath;
    		loaders.put(projPath, instance);
    	}
    		return loaders.get(projPath);
    	
    }
    
    /**
     * 加载相关类
     */
    public synchronized Class<?> loadClass(String className,boolean resolve)throws ClassNotFoundException{
    	Class<?> newClass ;
    	byte[] classData=null;
    	//检查是否已经加载
    	newClass = (Class<?>) loadedClasses.get(className);
    	if(newClass!=null){
    		if(resolve) this.resolveClass(newClass);
    		return newClass;
    	}
    	//如果还没有加载,那么第一件事则是去系统中加载
    	//之所以这么费事,是因为被加载的类可能用到系统类,根据约定这些
    	//系统类会被同一个classloader加载进来,所以必须加入以下代码
    	try {
			newClass =super.findSystemClass(className);
			if(resolve) this.resolveClass(newClass);
			return newClass;
		} catch (ClassNotFoundException e) {
			System.out.println(className.trim()+"并非系统类,将调用外部加载程序……");
		}
		//下面的是针对外部工程的加载程序
		try{
    	String classFileName = projectPath+Constant.PROJECT_CLASSES_PATCH+className.trim();
    	classData = getClassData(classFileName);
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		//如果是jsp
		if(null==classData){
		    System.out.println(className+" 不在工程目录下,开始尝试加载work文件夹");
		    String classFileName = projectPath+Constant.FILE_SP+className;
		    System.out.println("尝试加载"+classFileName);
	    	classData = getClassData(classFileName);
			}
		//对jar文件和路径还需要特殊加载
		if(null==classData){
	    System.out.println(className+" 不在/classes目录下,开始尝试加载jar文件");
		classData = loadFromJarFile(className);
		}
		//其他操作
		newClass = defineClass(null,classData,0,classData.length);
		loadedClasses.put(className, newClass);
		if(resolve) this.resolveClass(newClass);
		return newClass;
    	
    }
    /**
     * 从jar文件中返回class文件的字节数组,当返回值为null时,表示没找到对应类
     * @param className 类名
     * @return 以字节数组形式保存的类的内容
     */
    private synchronized byte[] loadFromJarFile(String className) {
    	String jarFilePatch = projectPath+Constant.PROJECT_JAR_PATCH;
    	File patch = new File (jarFilePatch);
    	if(patch.isDirectory())
    	{
    		File[] fileArray = patch.listFiles(new FileTypeFilter(Constant.FileType_SP_jar));
    		for(File jar:fileArray)
    		{
    		 byte[] values = getDataFromFile(jar,className);
    		 if(values!=null&&values.length>0) return values;
    		}
    	}
    	//否则返回null
		return null;
	}
	private byte[] getDataFromFile(File jar,String className) {
		className = className.replace(".", "/")+Constant.FileType_SP_Class;
		int length=0;
		byte[] data = new byte[1024*8];//8m的class文件,大小应该在改为从配置文件读取
		try {
			ZipFile jarFile = new ZipFile(jar);
			ZipEntry entity = jarFile.getEntry(className);
			InputStream in = jarFile.getInputStream(entity);
			length= in.read(data);
			//数据处理
			byte[] returnValue = new byte[length]; 
			System.arraycopy(data, 0, returnValue, 0, length);
			return returnValue;
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	/**
     * 获得类的内容 ,当返回值为null时,表示没找到对应类
     * 但是这个类现在有一个问题,当classFileName中含有
     * 作为非类分隔符而存在的'.'字符时,路径解析会不正确
     * @param classFileName
     * @return 字节数组
     */
	private synchronized byte[] getClassData(String classFileName) {
		byte[] data = new byte[1024*cacheSize];//8m的class文件,应该够大了吧
		int length=0;
		classFileName = classFileName.replace(".", "\\");
		classFileName+=Constant.FileType_SP_Class;
		System.out.println("正在加载" +classFileName);
		File classFile = new File(classFileName);
		if(!classFile.exists()||!classFile.canRead()) return null;
		try {
			FileInputStream in = new FileInputStream(classFile);
			length = in.read(data);
		} catch (Exception e) {
			e.printStackTrace();
		}
		byte[] returnValue = new byte[length]; 
		System.arraycopy(data, 0, returnValue, 0, length);
		return returnValue;
	}
}


tomcat的代码里面做了三个classloader,分别对应系统类、外部类和jar包,我的实现里只做了一个,这样会牺牲一些效率,但是在调用加载器的时候就不必在做复杂的判断了。
下面是servlet执行器代码,其中调用了新的classLoader
/**
 * @author:	    刘宇航			@create:	2009-4-13
 * @modifier:	刘宇航			@modify:	2009-4-13
 * @reviewer:	刘宇航			@review:	2009-4-13
 * 执行servlet的执行器
 */
package executor.impl;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import project.ProjectInfo;
import servlet.ServletInfo;
import util.Constant;
import util.LocalClassLoader;
import executor.CheckableExecutor;

public class ServletExecutor implements  CheckableExecutor {

	private ProjectInfo project;

	private ServletInfo info;

	public void init(ProjectInfo project) {
		this.project = project;
	}

	/**
	 * 执行servlet的方法体
	 */
	@Override
	public void forward(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// 执行部分
		ClassLoader loader = LocalClassLoader.getInstance(project.getPatch());
		HttpServlet servlet = (HttpServlet) loader.loadClass(
				info.getServletClass()).newInstance();
		// 先执行filter 然后是servlet本身
		FilterChain chain = info.getFilterChain();
		chain.doFilter(request, response);
		servlet.init(info.getServletConfig());
		servlet.service(request, response);
		servlet.destroy();
	}

	/**
	 * 判断资源是否可以执行
	 */
	@Override
	public boolean isExecutable(HttpServletRequest request) {
		//先创建ServletInfo对象
		ServletInfo info =getServletInfo(request);
		if(info != null)
		{
			this.info = info;
			return true;
		}
		else
			return false;
		
			
	}
	/**
	 * 匹配servlet
	 * @param request
	 * @return
	 */
	private ServletInfo getServletInfo(HttpServletRequest request) {
		for(ServletInfo info :project.getServletInfo())
		{
		 Pattern p = Pattern.compile(Constant.WEB_SP+project.getWebPath()+info.getUrl_pattern());
		 Matcher m = p.matcher(request.getRequestURI());
		 if(m.matches()) return info;
		}
		return null;
	}
}

呵呵,这样我们的服务器就从web服务器进化到servlet容器了:》
不过我贴出来的代码只是比较关键的类,至于数据结构,有经验的程序员应该很容易猜出来——全局有一个appRuntime类,里面包含了若干个projectInfo类(储存项目信息),projectInfo里储存了每个web项目中web.xml文件的信息,包括servlet与路径的对应关系等等。
好久不写东西了,语言和思维有一些僵硬,慢慢来吧,下一章打算贴一点http协议解析的东西。
0
0
分享到:
评论

相关推荐

    Fried Cake Application Server-开源

    作为一个处于开发和测试阶段的小型容器,Fried Cake Server为开发者提供了在JSP(JavaServer Pages)环境中的部署和管理应用的新选择。 J2EE,全称Java 2 Platform, Enterprise Edition,是由Oracle公司主导的Java...

    台湾小吃英文名称(Word档含图文).doc

    - 萝卜糕:Turnip Cake 或 Fried White Radish Patty - 盐鸭蛋:Salted Duck Egg - 锅贴:Fried Dumpling - 馍头:Steamed Bun - 葱油饼:Spring Onion Pancake - 饺子:Dumpling - 稀饭(粥):Rice ...

    transLucid (was Lucid Fried Eggs)-开源

    "transLucid (was Lucid Fried Eggs)" 这个标题表明这是一个名为 "transLucid" 的项目,之前可能被称为 "Lucid Fried Eggs"。这可能是因为项目经历了改名或更新,通常这样的变化伴随着软件的发展或品牌重塑。"开源" ...

    Rework - Jason Fried.rar

    GOMake a dent in the universeScratch your own itchStart making somethingNo time is no excuseDraw a line in the sandMission statement impossibleOutside money is Plan ZYou need less than you thinkStart ...

    Fried衰弱评估方法.pdf

    Fried衰弱评估方法.pdf

    qtip:简单的文本显示服务

    QTip QTip是通过命令行管理的自托管... qtip serve /recipe/fried-chicken fried-chicken-recipe.md 产品特点 Markdown文件支持 自动将markdown中嵌入的本地图像上传和存储到您的首选CDN 100%自托管 :rocket: 演示版

    最全版我国菜名英文翻译(数千种).doc

    - 蔬菜类:如蒜蓉西兰花(Stir-Fried Broccoli with Garlic) - 豆腐类:如豆腐烧肉(Stewed Tofu with Pork) - 燕窝类:如燕窝羹(Bird's Nest Soup) - 羹汤煲类:如西红柿牛腩汤(Beef Stew with Tomatoes)...

    Fried Rice-开源

    自动正确地回答来自www.freerice.com的问题,从而向联合国提供了大量大米,以养活世界。

    高二烹饪班英语毕业考试题.docx

    5. 煎蛋火鸡 - Fried egg with turkey 6. 饺子 - Dumplings 7. 甜品 - Dessert 8. 三明治 - Sandwich 9. 比萨 - Pizza 10. 汉堡 - Hamburger 11. 蛋糕 - Cake 12. 西瓜 - Watermelon 13. 梨 - Pear 14. 橙子 - ...

    国外生活必备英文词汇_饮食篇.doc

    - French fries:炸薯条,切片的土豆油炸而成。 - baked potato:烘马铃薯,整个土豆烘烤至软糯。 - mashed potatoes:马铃薯泥,捣碎的煮熟土豆。 - omelette:简蛋卷,煎熟的鸡蛋卷。 - pudding:布丁,甜点,通常...

    餐厅英语情景对话-必备.doc

    - "I recommend crispy and fried duck."(我推荐香酥鸭。) 这些对话涵盖了餐厅服务的基本流程,包括迎接顾客、询问需求、推荐菜品、预订和等待座位、以及就座后的点餐过程。了解这些常用表达对于在餐厅工作的...

    epOS:用于Intel x86处理器的教育性操作系统

    环0-3内核与用户空间分离 交流会 APIC / IOAPIC APIC计时器 完整的vsprintf实现(无浮点数:) 进行中 PS / 2键盘驱动程序(8042) 待办事项 添加测试框架 先决条件 编译:$ sudo pacman -S grub mtools nasm ...

    广东省深圳市文汇中学2015届九年级英语上学期第6周周末作业(答案不全) 牛津深圳版

    - `油炸食品`: fried food - `体检`: physical examination - `减肥`: lose weight - `通常;大体上`: usually; generally - `加糖的咖啡`: sugary coffee - `a bit of`: 一点点 - `would rather do sth.`: ...

    中国菜英文翻译2.doc

    * 萝卜糕(Fried white radish patty) * 芋头糕(Taro cake) 特殊饮料 * 果汁甘蔗汁(Sugar cane juice) * 酸梅汁(Plum juice) * 杨桃汁(Star fruit juice) * 青草茶(Herb juice) 特殊点心 * 当归鸭...

    第六单元教案IlikemusicthatIcandanceto单元学案.pdf

    - 我不愿意吃太多的油炸食品:I am unwilling to eat too much fried food. - 主要是膳食平衡:mainly a balanced diet - 我同意多吃水果和蔬菜对身体好:I agree that eating more fruits and vegetables is ...

    TPO听力按学科分类词汇.doc

    - **Deep Fried Food**:油炸食品。 #### 七、注册办公室场景词汇 - **Fieldwork/Research**:实地调查或研究项目。 - **Academic Record**:学业成绩记录。 - **Financial Aid**:经济援助,包括奖学金和其他形式...

    fire-containment:Fried和Fried描述的火势遏制和初始攻击模型

    cbevins /消防设施一种基于1995年杰里米·弗里德(Jeremy S.Fried)和伯顿·弗雷德(Burton D.Fried)论文的火遏制算法和初始攻击模型,题为“用现实战术模拟野火遏制”。 它是根据Jeremy S.Fried(1991)的FCAT防火...

    TPO听力按学科分类词汇.docx

    - **Deep-fried food**:油炸食品。 - **Registrar’s Office**:注册办公室,处理课程注册和成绩记录。 - **Fieldwork/research**:实地研究,学术研究的一部分。 - **Academic record**:学业成绩记录。 - **...

    (课标卷)2014-2015学年高中英语 Unit 2 Healthy eating Warming Up Reading课时作

    - fried:油炸的,指通过热油烹制的食物。 - balanced:平衡的,形容饮食均衡,包含各种必要的营养成分。 - slim:苗条的,形容身材瘦削,符合现代审美标准。 2. 单项选择题: - interested:感兴趣的,用于...

Global site tag (gtag.js) - Google Analytics