资源执行架构……说的有一点儿玄了,实话实说,所谓的资源执行架构在最初仅仅是一群if……else语句而已,随着开发的进行它们变得越来越大,到最后实在是糟糕透顶。还记得上一篇的SocketProcess类么?最早它可是包含了执行方法的,很麻烦、很罗嗦、更要命的是不易扩展:
这才是第一版的资源执行器,很凌乱吧
后来我把资源执行架构进行了重整,做了一个代理模式
这个架子由两个接口、一个代理类和若干实现类组成
第一个是执行器接口,实现了这个接口的类才能接受http请求并进行应答
再来是执行代理类,这个类用了个责任链模式,其实这个executorArray是可以配到配置文件里的,但是目前还没考虑那么远的事情,所以先这么放着了。不过想要扩展依然是比较容易的,实现一个CheckableExecutor 接口,再把类名填在executorArray数组中注册,就可以加入到执行序列里了
接下来是三个实现类,由JspExecutor、ServletExecutor和ResourceExecutor组成
分别对应jsp资源、servlet资源和普通文件资源,但是前两个执行器涉及到环境外的类加载、jsp编译、系统数据结构等诸多问题,我会放到稍后的章节
下面是普通的资源执行器
我review了一下,除了“String fileName = RequestHanler.loadRealPath(request);”这一句外,其他的应该都没有疑问。至于这一句,就是从request url到文件资源的映射,一开始的时候仅仅是做简单的文件夹路径映射就好,后来我把它跟项目装载器ProjectDeployer做了一些关联,不过这个实现不重要,大家应该看得懂。
那么,有了这几了类,我们的油炸糕应该就可以进行一些简单的应答了……
有兴趣的朋友可以自己写一个试试,其实这一步,并不难做到,难的是后面……
呵呵,下期会介绍远端classLoader的写法和server的数据结构,慢慢来
package server; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; 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 javax.servlet.http.HttpSession; import jsp.JspConvertor; import project.ProjectInfo; import servlet.bean.ServletInfo; import util.Constant; import util.HttpError; import util.LocalClassLoader; import util.ServerMessage; import webHttp.HttpRequestImpl; import webHttp.HttpResponseImpl; import webHttp.RequestHanler; import webHttp.SessionPool; /** * 双线通信线程 * 解释: 双线通信指,既接收请求,又返回响应 * 相对应的还有 单向发送通讯 和 单向接受通讯 * 后两个可以用于jms等功能的实现 * 目前尚未考虑实现 * @author 刘宇航 * */ public class SocketProcess extends Thread { ServerSocketChannel serverSocket = null; /** * 初始化一个线程 * @param serverSocket 必须保证双线通信 */ public SocketProcess(ServerSocketChannel serverSocket) { this.serverSocket = serverSocket; } /** * 从serverSocket中获取数据 * 然后判断是资源文件还是servlet * 最有发送正确的信息给客户端 */ public void run() { ByteBuffer buffer = ByteBuffer.allocate(1024 * 8); SocketChannel channel = null; try { // 一些读取数据的工作 channel = serverSocket.accept(); if (channel != null && channel.read(buffer) > 0) { String requestInfo = new String(buffer.array(), 0, buffer .position()); HttpRequestImpl request = RequestHanler .getHttpRequest(requestInfo); AppRunTime runtime = AppRunTime.getInstance(); String[] uri = request.getContextPath().split(Constant.WEB_SP); ProjectInfo project = runtime.getProjectMap().get(uri[1]); if(project==null)return; //绑定session SessionPool sessionPool = SessionPool.getInstance(project.getId()); HttpSession session = sessionPool.getSession(channel.socket().getInetAddress().getHostAddress()); request.bind(session); // 先尝试执行servlet if(excuteServlet(channel, project, request)==false) { //判断是否是jsp if(request.getServletPath().endsWith(Constant.FileType_SP_JSP)) excuteJsp(channel, project, request); //否则的话按照普通资源进行解析 else excuteResource(channel, project, request); } // 至少要反回空串 buffer.clear(); if (channel.isOpen()) { buffer.put(" ".getBytes()); buffer.flip(); channel.write(buffer); channel.finishConnect(); channel.close(); } } } catch (Exception e) { e.printStackTrace(); } } /** * 编译并执行执行jsp资源 * @param channel 获得的非阻塞通道 * @param project 所属项目信息 * @param request 当前请求 */ private void excuteJsp(SocketChannel channel, ProjectInfo project, HttpServletRequest request) { String fileName = RequestHanler.loadRealPath(request); File jspFile = new File(fileName); //如果jsp不存在的话 if(!jspFile.exists()) { sendExceptionMessage(channel,HttpError.ERROR_404); return; } JspConvertor convertor = new JspConvertor(jspFile,project); try { File servletFile = convertor.getCompiledServlet(); ClassLoader loader = LocalClassLoader.getInstance(servletFile.getParent()); HttpServlet servlet = (HttpServlet) loader.loadClass(servletFile.getName().replace(Constant.FileType_SP_Class, "")).newInstance(); HttpServletResponse response = new HttpResponseImpl(channel); servlet.service(request, response); } catch (Exception e) { sendExceptionMessage(channel,HttpError.ERROR_404); } } /** * 向客户端浏览器报告错误,比如error404 page not found之类的 * @param channel * @param message */ private void sendExceptionMessage(SocketChannel channel ,String message){ ByteBuffer buffer = ByteBuffer.allocate(1024 * 8); buffer.put(HttpError.ERROR_404.getBytes()); buffer.flip(); try { channel.write(buffer); } catch (IOException e) { System.err.println(ServerMessage.connection_exception); } buffer.clear(); } /** * 执行普通资源 * * @param channel 获得的非阻塞通道 * @param project 所属项目信息 * @param request 当前请求 * @throws Exception 任何意外 */ private void excuteResource(SocketChannel channel, ProjectInfo project, HttpServletRequest request) throws Exception { ByteBuffer buffer = ByteBuffer.allocate(1024 * 8); String fileName = RequestHanler.loadRealPath(request); buffer.clear(); File file = new File(fileName); if (file.exists() && file.canRead()) { FileChannel fc = new FileInputStream(file).getChannel(); while (fc.read(buffer) > 0) { buffer.flip(); channel.write(buffer); buffer.clear(); } } else {// 如果还是找不到资源,那么只能报404 page not found 错误了 sendExceptionMessage(channel,HttpError.ERROR_404); } } /** * 执行servlet资源 * * @param channel 获得的非阻塞通道 * @param project 所属项目信息 * @param request 当前请求 * @return 是否已经有 servlet被执行 * @throws Exception if 任何意外 */ private boolean excuteServlet(SocketChannel channel, ProjectInfo project,HttpServletRequest request) throws Exception { 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()==false) continue; //执行部分 ClassLoader loader = LocalClassLoader.getInstance(project .getPatch()); HttpServlet servlet = (HttpServlet) loader.loadClass( info.getServletClass()).newInstance(); HttpServletResponse response = new HttpResponseImpl(channel); //先执行filter 然后是servlet本身 FilterChain chain = info.getFilterChain(); chain.doFilter(request, response); servlet.init(info.getServletConfig()); servlet.service(request, response); servlet.destroy(); return true; } return false; } }
这才是第一版的资源执行器,很凌乱吧
后来我把资源执行架构进行了重整,做了一个代理模式
这个架子由两个接口、一个代理类和若干实现类组成
第一个是执行器接口,实现了这个接口的类才能接受http请求并进行应答
public interface Executor { /** * 执行资源,这个方法只执行单向资源 * 如果日后需要扩展,比如添加返回值之类的 * 请另外写方法接口 * @param request 请求对象 * @param response 应答对象 */ public void forward(HttpServletRequest request,HttpServletResponse response) throws Exception; }第二个接口是Executor 的子接口CheckableExecutor 实现了它的类可以进行判断是否可以执行
public interface CheckableExecutor extends Executor{ public void init(ProjectInfo project); /** * 判断是否可以执行该资源 * @return */ public boolean isExecutable(HttpServletRequest request); }
再来是执行代理类,这个类用了个责任链模式,其实这个executorArray是可以配到配置文件里的,但是目前还没考虑那么远的事情,所以先这么放着了。不过想要扩展依然是比较容易的,实现一个CheckableExecutor 接口,再把类名填在executorArray数组中注册,就可以加入到执行序列里了
package executor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import project.ProjectInfo; import executor.impl.JspExecutor; import executor.impl.ResourceExecutor; import executor.impl.ServletExecutor; public class BaseExecutor implements Executor { @SuppressWarnings("unchecked") private Class<CheckableExecutor>[] executorArray = new Class[]{JspExecutor.class,ServletExecutor.class,ResourceExecutor.class}; //传给executor private ProjectInfo project; /** * 构造方法 * @param project */ public BaseExecutor(ProjectInfo project){ this.project = project; } /** * 获得相应的执行器实现 * 这个方法可以相应的扩展 * @param request * @return * @throws Exception * @throws InstantiationException */ public Executor getExecutor(HttpServletRequest request) throws InstantiationException, Exception { //选择执行器 for(Class<CheckableExecutor> exeClass:executorArray) { CheckableExecutor executor = exeClass.newInstance(); executor.init(project); if(executor.isExecutable(request)) return executor; } return null; } /** * 先找到执行器的实现,然后再执行资源 */ @Override public void forward(HttpServletRequest request,HttpServletResponse response) throws Exception{ Executor exe = getExecutor(request); exe.forward(request, response); } }
接下来是三个实现类,由JspExecutor、ServletExecutor和ResourceExecutor组成
分别对应jsp资源、servlet资源和普通文件资源,但是前两个执行器涉及到环境外的类加载、jsp编译、系统数据结构等诸多问题,我会放到稍后的章节
下面是普通的资源执行器
package executor.impl; import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import project.ProjectInfo; import util.HttpError; import webHttp.RequestHanler; import exceptions.HttpException; import executor.CheckableExecutor; public class ResourceExecutor implements CheckableExecutor { public void init(ProjectInfo project) { //什么都不做 } /** * 执行普通资源 */ @Override public void forward(HttpServletRequest request, HttpServletResponse response) throws Exception { ByteBuffer buffer = ByteBuffer.allocate(1024 * 8); String fileName = RequestHanler.loadRealPath(request); buffer.clear(); File file = new File(fileName); if (file.exists() && file.canRead()) { FileChannel fc = new FileInputStream(file).getChannel(); while (fc.read(buffer) > 0) { buffer.flip(); response.getOutputStream().write(buffer.array()); buffer.clear(); } } else {// 如果还是找不到资源,那么只能报404 page not found 错误了 throw new HttpException(HttpError.ERROR_404); } } @Override /** * 返回这个执行器是否可以执行 * ResourceExecutor,是所有执行器的最后一步,并且包含了容错,所以当然是可以执行的 */ public boolean isExecutable(HttpServletRequest request) { return true; } }
我review了一下,除了“String fileName = RequestHanler.loadRealPath(request);”这一句外,其他的应该都没有疑问。至于这一句,就是从request url到文件资源的映射,一开始的时候仅仅是做简单的文件夹路径映射就好,后来我把它跟项目装载器ProjectDeployer做了一些关联,不过这个实现不重要,大家应该看得懂。
那么,有了这几了类,我们的油炸糕应该就可以进行一些简单的应答了……
有兴趣的朋友可以自己写一个试试,其实这一步,并不难做到,难的是后面……
呵呵,下期会介绍远端classLoader的写法和server的数据结构,慢慢来
相关推荐
在当前的压缩包文件中,我们看到了“fried cake server”这一文件名,这很可能是项目的主要代码库或者可执行文件。对于想要尝试或贡献的人来说,下载并解压这个文件,然后按照开发者提供的指南进行编译和安装,就能...
- 萝卜糕:Turnip Cake 或 Fried White Radish Patty - 盐鸭蛋:Salted Duck Egg - 锅贴:Fried Dumpling - 馍头:Steamed Bun - 葱油饼:Spring Onion Pancake - 饺子:Dumpling - 稀饭(粥):Rice ...
"transLucid (was Lucid Fried Eggs)" 这个标题表明这是一个名为 "transLucid" 的项目,之前可能被称为 "Lucid Fried Eggs"。这可能是因为项目经历了改名或更新,通常这样的变化伴随着软件的发展或品牌重塑。"开源" ...
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 ...
QTip QTip是通过命令行管理的自托管... qtip serve /recipe/fried-chicken fried-chicken-recipe.md 产品特点 Markdown文件支持 自动将markdown中嵌入的本地图像上传和存储到您的首选CDN 100%自托管 :rocket: 演示版
Fried衰弱评估方法.pdf
自动正确地回答来自www.freerice.com的问题,从而向联合国提供了大量大米,以养活世界。
5. 煎蛋火鸡 - Fried egg with turkey 6. 饺子 - Dumplings 7. 甜品 - Dessert 8. 三明治 - Sandwich 9. 比萨 - Pizza 10. 汉堡 - Hamburger 11. 蛋糕 - Cake 12. 西瓜 - Watermelon 13. 梨 - Pear 14. 橙子 - ...
- fried:油炸的,指通过热油烹制的食物。 - balanced:平衡的,形容饮食均衡,包含各种必要的营养成分。 - slim:苗条的,形容身材瘦削,符合现代审美标准。 2. 单项选择题: - interested:感兴趣的,用于...
2. **Asset Security**:资产安全部分涉及物理安全措施、数据分类与保护技术。 - 物理安全控制 - 数据加密与保护 - 资产所有权与访问控制机制 3. **Security Engineering**:这部分内容探讨了安全工程原理、系统...
cbevins /消防设施一种基于1995年杰里米·弗里德(Jeremy S.Fried)和伯顿·弗雷德(Burton D.Fried)论文的火遏制算法和初始攻击模型,题为“用现实战术模拟野火遏制”。 它是根据Jeremy S.Fried(1991)的FCAT防火...
2. 强调口感、烹饪方法和主料: - 如"鱼香肉丝"(fried shredded pork with Sweet and Sour sauce),既表明口感又指明烹饪方法 通过这些翻译策略,我们可以更好地向国际观众展示中国餐饮文化的魅力,并确保他们在...
epOS,Ramon Fried(2013-2016)的教育版英特尔8086 32位操作系统 强调 兼容Multiboot 1.0 位图页面框架分配器 高半内核 分页已启用 使用循环算法的可抢占式调度 环0-3内核与用户空间分离 交流会 APIC / IOAPIC ...
在中国菜英文翻译2.doc文件中,我们可以找到很多关于中国菜的英文翻译信息。以下是从文件中提取的知识点: 中式早点 * 烧饼(Clay oven rolls) * 油条(Fried bread stick) * 韭菜盒(Fried leek dumplings) * ...
- 甜品及其他西点:如巧克力蛋糕(Chocolate Cake) 4. **饮品和酒类**: - 中国酒:如黄酒(Yellow Wine),白酒(Liquor) - 葡萄酒:如干红(Dry Red Wine) - 洋酒:如威士忌(Whisky),白兰地(Brandy) ...
- French fries:炸薯条,切片的土豆油炸而成。 - baked potato:烘马铃薯,整个土豆烘烤至软糯。 - mashed potatoes:马铃薯泥,捣碎的煮熟土豆。 - omelette:简蛋卷,煎熟的鸡蛋卷。 - pudding:布丁,甜点,通常...
- `油炸食品`: fried food - `体检`: physical examination - `减肥`: lose weight - `通常;大体上`: usually; generally - `加糖的咖啡`: sugary coffee - `a bit of`: 一点点 - `would rather do sth.`: ...
- "I recommend crispy and fried duck."(我推荐香酥鸭。) 这些对话涵盖了餐厅服务的基本流程,包括迎接顾客、询问需求、推荐菜品、预订和等待座位、以及就座后的点餐过程。了解这些常用表达对于在餐厅工作的...
- 我不愿意吃太多的油炸食品:I am unwilling to eat too much fried food. - 主要是膳食平衡:mainly a balanced diet - 我同意多吃水果和蔬菜对身体好:I agree that eating more fruits and vegetables is ...