• 一个servlet web server,由移植自Tomcat的完整的connector模块和简化的Container(取代servlet处理器)组成


      背景:连接器模块由此已经完整,Tomcat中连接器已经有完善的线程、异常处理和Http处理(res/req解析),只是之前的servlet处理器还是很简单,现在作为学习Container的一个预热,写一个简单的container取代servlet,由主程序初始化并启动Tomcat连接器,创建container传递给连接器。这次演进,程序的大体运行方向较之前其实是不变的:等待连接、解析socket、创建res/req,"组装"(动态加载)程序员编写的servlet并处理,清理res/req,关闭socket、停止线程。不同的是,servlet处理器不仅要演进得更完善(成为container)而且还要和连接器解耦。通过连接器源码《setContainer(Container container)》可以发现,contaner被其关联,container的创建初始化工作是由专门            程序来完成,虽然它需要依赖container的getContainer().invoke(this.request, this.response)来执行“组装”servlet的子程序。       (getContainer().invoke(this.request,this.response)是模块的连接处也是程序输入输出的入口,对研究源码很关键;connector.initialize()和connector.start()是连接器执行的入口。牢牢记住,感谢作者,百万行的代码中截取某些程序入口真的是很难,也可能是我功力不够,没找到方法)。

    • 代码目录

        附加说明:这里直接引入源码供主程序调用,classpath编译运行这些依赖,即我所谓的移植Tomcat源码。

    • Bootstrap
    package startup;
    
    import core.SimpleContainer;
    
    import org.apache.catalina.connector.http.HttpConnector;
    
    public final class Bootstrap {
      public static void main(String[] args) {
        HttpConnector connector = new HttpConnector();//创建连接对象
        SimpleContainer container = new SimpleContainer();//创建容器
        connector.setContainer(container);//放进连接对象
        try {
          connector.initialize();//初始化 并启动,这里可是使用生命周期,然后执行即可,应该是?!
          connector.start();
    
          // make the application wait until we press any key.
          System.in.read();
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    View Code
    • simpleContainer
    package core;
    
    import java.beans.PropertyChangeListener;
    
    
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.net.URLStreamHandler;
    import java.io.File;
    import java.io.IOException;
    import javax.naming.directory.DirContext;
    import javax.servlet.Servlet;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.catalina.Cluster;
    import org.apache.catalina.Container;
    import org.apache.catalina.ContainerListener;
    import org.apache.catalina.Loader;
    import org.apache.catalina.Logger;
    import org.apache.catalina.Manager;
    import org.apache.catalina.Mapper;
    import org.apache.catalina.Realm;
    import org.apache.catalina.Request;
    import org.apache.catalina.Response;
    
    public class SimpleContainer implements Container {
    
      public static final String WEB_ROOT =
        System.getProperty("user.dir") + File.separator  + "webroot";//资源地址
    
      public SimpleContainer() {
      }
    
      public String getInfo() {
        return null;
      }
    
      public Loader getLoader() {
        return null;
      }
    
      public void setLoader(Loader loader) {
      }
    
      public Logger getLogger() {
        return null;
      }
    
      public void setLogger(Logger logger) {
      }
    
      public Manager getManager() {
        return null;
      }
    
      public void setManager(Manager manager) {
      }
    
      public Cluster getCluster() {
        return null;
      }
    
      public void setCluster(Cluster cluster) {
      }
    
      public String getName() {
        return null;
      }
    
      public void setName(String name) {
      }
    
      public Container getParent() {
        return null;
      }
    
      public void setParent(Container container) {
      }
    
      public ClassLoader getParentClassLoader() {
        return null;
      }
    
      public void setParentClassLoader(ClassLoader parent) {
      }
    
      public Realm getRealm() {
        return null;
      }
    
      public void setRealm(Realm realm) {
      }
    
      public DirContext getResources() {
        return null;
      }
    
      public void setResources(DirContext resources) {
      }
    
      public void addChild(Container child) {
      }
    
      public void addContainerListener(ContainerListener listener) {
      }
    
      public void addMapper(Mapper mapper) {
      }
    
      public void addPropertyChangeListener(PropertyChangeListener listener) {
      }
    
      public Container findChild(String name) {
        return null;
      }
    
      public Container[] findChildren() {
        return null;
      }
    
      public ContainerListener[] findContainerListeners() {
        return null;
      }
    
      public Mapper findMapper(String protocol) {
        return null;
      }
    
      public Mapper[] findMappers() {
        return null;
      }
    
      public void invoke(Request request, Response response)
        throws IOException, ServletException {
    
        String servletName = ( (HttpServletRequest) request).getRequestURI();//获得要请求的servlet
        servletName = servletName.substring(servletName.lastIndexOf("/") + 1);
        URLClassLoader loader = null;//类加载器被直接创建,加载模块与其他模块的关系类似工具模块
        try {
          URL[] urls = new URL[1];
          URLStreamHandler streamHandler = null;
          File classPath = new File(WEB_ROOT);//将资源文件创建为file
          String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;//路径传递给url对象
          urls[0] = new URL(null, repository, streamHandler);
          loader = new URLClassLoader(urls);//初始化servlet加载器
        }
        catch (IOException e) {
          System.out.println(e.toString() );
        }
        Class myClass = null;
        try {
          myClass = loader.loadClass(servletName);//加载用户请求的servlet
        }
        catch (ClassNotFoundException e) {
          System.out.println(e.toString());
        }
    
        Servlet servlet = null;
    
        try {
          servlet = (Servlet) myClass.newInstance();//初始化,并传递res/req,组件得以装载
          servlet.service((HttpServletRequest) request, (HttpServletResponse) response);
        }
        catch (Exception e) {
          System.out.println(e.toString());
        }
        catch (Throwable e) {
          System.out.println(e.toString());
        }
    
    
    
      }
    
      public Container map(Request request, boolean update) {
        return null;
      }
    
      public void removeChild(Container child) {
      }
    
      public void removeContainerListener(ContainerListener listener) {
      }
    
      public void removeMapper(Mapper mapper) {
      }
    
      public void removePropertyChangeListener(PropertyChangeListener listener) {
      }
    
    }
    View Code

    总结:Bootstarp类作为主程序,只要抓住启动入口就可以了,传入container给connector,再初始化、运行connector,记住传递依赖在先,顺序很重要;simpleContainer类当前只   有invoke方法,执行了加载动作,其他方法暂时为null。现在,一个简单的Container就算完成了,本案例作为容器和连接器关系的一个记录,哪天记不清了就回顾一下。

       这里少了一个servlet.jar包,因为导入的是弃用版本Eclipse给屏蔽了!

  • 相关阅读:
    初学Cocos2dx
    炸弹人NABCD分析
    求二维整数数组中最大联通子数组的和
    大道之简读书笔记1
    求首位相连二维数组最大子矩阵的和
    求首位相连一维数组最大子数组的和
    求二维数组最大子数组的和
    程序员修炼之道读后感3
    电梯调度需求分析
    课堂作业第四周课上作业二
  • 原文地址:https://www.cnblogs.com/10000miles/p/9233736.html
Copyright © 2020-2023  润新知