Jetty的Server创建与启动

其实不管是tomcat还是jetty,他们在启动的时候要做的事情都差不太多。。。无非就是下面的内容:

(1)创建用于连接的connector,创建线程池,

(2)扫描当前的web程序的部署目录,为他们创建上下文环境,并对他们进行path的路由设置

(3)初始化创建的web程序上下文,这里就包括创建servlet啥的。,初始化linstener啥的。并做好自己的path路由

(4)启动connector,开始监听,整个server开始运行。。。。

好了,接下来来分析一下jetty的启动过程吧,其实启动的过程也要分为好几种的,这里就拿最常用的来说吧,也就是在jetty服务器下同时部署多个webapp,因而jetty需要分别为这些webApp创建他们的context。。


来看启动的代码吧:

[java] view plaincopy
  1. Server server = new Server();  //创建爱你server  
  2. ContextHandlerCollection contexts = new ContextHandlerCollection();  //创建一个contextHandler的collection  
  3. server.setHandler(contexts);  //设置handler,这个就是contextHandlercollection,它用于保存所有的WebAppContext  
  4. //SelectChannelConnector connector = new SelectChannelConnector();  
  5. SocketConnector connector = new SocketConnector();  //创建connector,这里其实应该是要选用nio的connector比较好才对  
  6. String address = args[0];  
  7. int colon = address.lastIndexOf(':');  
  8. //设置connector的端口地址信息  
  9. if (colon<0) {  
  10.     connector.setPort(Integer.parseInt(address));    
  11. }  else {  
  12.     connector.setHost(address.substring(0,colon));  
  13.     connector.setPort(Integer.parseInt(address.substring(colon+1)));  
  14. }  
  15. server.setConnectors(new Connector[]{connector});  
  16.   
  17. if (args.length<3) {  
  18.     ContextHandler context = new ContextHandler();  
  19.     context.setContextPath(URIUtil.SLASH);  
  20.     context.setResourceBase(args.length==1?".":args[1]);  
  21.     ServletHandler servlet = new ServletHandler();  
  22.     servlet.addServletWithMapping("org.mortbay.jetty.servlet.DefaultServlet", URIUtil.SLASH);  
  23.     context.setHandler(servlet);  
  24.     contexts.addHandler(context);  
  25. else if ("-webapps".equals(args[1])) {  //这里是同时启动多个app  
  26.     WebAppContext.addWebApplications(server, args[2], WebAppContext.WEB_DEFAULTS_XML, truetrue);  
  27. else if ("-webapp".equals(args[1])) {  
  28.     WebAppContext webapp = new WebAppContext();  
  29.     webapp.setResourceBase(args[2]);  
  30.     webapp.setContextPath(URIUtil.SLASH);  
  31.     contexts.addHandler(webapp);  
  32.       
  33. }  
  34.       
  35. server.start();  //启动,说白了就是启动connector,里面的contextHandler啥的  

本身看起来还是很简单的吧,首先是创建一个server对象,然后创建ContextHandlerCollection对象,这个我们在以前说过,它将会用于管理所有的WebAppContext,并对http请求进行路由,将他们交给相应的webAppContext来处理。。然后这里创建了connector对象,貌似默认用的还是之前分析过的SocketConnector,也就是bio的connector,其实这里应该不用他才对,因为毕竟还有性能够好的nio实现的SelectChannelConnector。。。。

然后就是设置connector的监听地址,端口一类的信息。。。

对于有多个app的启动,应该是要分析如下的代码:

[java] view plaincopy
  1. WebAppContext.addWebApplications(server, args[2], WebAppContext.WEB_DEFAULTS_XML, truetrue);  

这里直接调用了一个类方法来进行处理的。。那么我们来看看这个方法是怎么搞的吧:

[java] view plaincopy
  1. //自动的添加web程序到服务器,war或者文件夹的名字将会成为context的名字  
  2. //defaults是默认的xml路径  
  3. public static void addWebApplications(Server server,  
  4.                                       String webapps,  //用于存放app的路径  
  5.                                       String defaults,  
  6.                                       boolean extract,  
  7.                                       boolean java2CompliantClassLoader)  
  8.     throws IOException  
  9. {  
  10.     addWebApplications(server, webapps, defaults, __dftConfigurationClasses, extract, java2CompliantClassLoader);  
  11. }  

这里传进来的server对象就是前面创建的server对象,webapps是我们用来存放app代码的地方,待会将会扫描这个目录,然后为这些app创建webAppContext,default是默认的jetty服务器的配置文件路径,extract表示是否要解压war包,

好了这里依然是调用了一个类方法来执行的。。接下去看吧:

[java] view plaincopy
  1. public static void addWebApplications(Server server,  
  2.                                       String webapps,  
  3.                                       String defaults,  
  4.                                       String[] configurations,  
  5.                                       boolean extract,  
  6.                                       boolean java2CompliantClassLoader)  
  7.     throws IOException {  
  8.     //这里可以理解为存放context的容器,毕竟同一个jetty下面可能启动多个web程序  
  9.     //server在创建之后一般都会为其创建ContextHandlerCollection,所以这里就能够获取它  
  10.     HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);  
  11.     if (contexts==null) {  
  12.         contexts = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class);  
  13.     }  
  14.       
  15.     addWebApplications(contexts,webapps,defaults,configurations,extract,java2CompliantClassLoader);  
  16. }      

这个好像比较囧,。其实主要是后去了ConextHandlerCollection对象,然后再进行下一步的动作。。好吧。

[java] view plaincopy
  1.  public static void addWebApplications(HandlerContainer contexts,  
  2.                                        String webapps,  
  3.                                        String defaults,  
  4.                                        String[] configurations,    
  5.                                        boolean extract,  
  6.                                        boolean java2CompliantClassLoader)  
  7.      throws IOException  
  8.  {  
  9.      Log.warn("Deprecated configuration used for "+webapps);  
  10.      WebAppDeployer deployer = new WebAppDeployer();  
  11.      deployer.setContexts(contexts);  //设置context的容器,ContextHandlerCollection  
  12.      deployer.setWebAppDir(webapps);  //设置app存放的路径,也就是类似于war包的存放路径  
  13.      /* 
  14.       * org.mortbay.jetty.webapp.WebInfConfiguration 
  15. org.mortbay.jetty.webapp.WebXmlConfiguration 
  16. org.mortbay.jetty.webapp.JettyWebXmlConfiguration 
  17. org.mortbay.jetty.webapp.TagLibConfiguration 
  18.       */  
  19.      //这是一些默认的配置对象的类型,在启动的时候会创建这些对象用于webAppContext的创建  
  20.      deployer.setConfigurationClasses(configurations);  
  21.      deployer.setExtract(extract);  //是否要解压war  
  22.      deployer.setParentLoaderPriority(java2CompliantClassLoader);  
  23.      try  
  24.      {  
  25.          deployer.start();  
  26.      }  
  27.      catch(IOException e)  
  28.      {  
  29.          throw e;  
  30.      }  
  31.      catch(Exception e)  
  32.      {  
  33.          throw new RuntimeException(e);  
  34.      }  
  35.  }  

这段代码就稍微有一些干货了。。这里可以看到,创建了一个WebAppDeployer对象,这个我们可以将其理解为一个工具类,那些app的部署的事情就交给它去做了。。。

为其设置了ContextHandlerCollection,然后设置了当前app所在的根目录,并且这只了app启动时候用到的配置类型。。。。然后再执行它的start方法。。。

好了,接下来的事情就是扫描app的目录,然后为他们创建WebAppContext,并对他们进行初始化的一些工作了。。。这里就先停住吧。。。毕竟这个是app的创建和启动,而不是server的启动。。

那么回归到最开始的代码来看看server的start过程吧:

[java] view plaincopy
  1. protected void doStart() throws Exception  
  2. {  
  3.     Log.info("jetty-"+_version);  
  4.     HttpGenerator.setServerVersion(_version);  
  5.     MultiException mex=new MultiException();  
  6.     
  7.     //一些依赖的启动。。不过好像一般也没有啥吧  
  8.     for (int i=0;_realms !=null && i<_realms.length; i++) {  
  9.         if (_realms[i] instanceof LifeCycle) {  
  10.             ((LifeCycle)_realms[i]).start();  
  11.         }  
  12.     }  
  13.   
  14.     Iterator itor = _dependentLifeCycles.iterator();  
  15.     while (itor.hasNext()) {     
  16.         try{  
  17.             ((LifeCycle)itor.next()).start();   
  18.         }  
  19.         catch (Throwable e) {mex.add(e);}  
  20.     }  
  21.       
  22.     //创建线程池,其实感觉jetty的线程池的实现挺简陋的,跟netty的比起来  
  23.     if (_threadPool==null) {  
  24.         QueuedThreadPool tp=new QueuedThreadPool();  
  25.         setThreadPool(tp);  
  26.     }  
  27.       
  28.     //启动sessionManager,不过很少有一开始设置sessionManager的吧,一般都是在创建WebAppContext的时候自己创建的  
  29.     if (_sessionIdManager!=null) {  
  30.         _sessionIdManager.start();  
  31.     }  
  32.       
  33.     try  {  
  34.         //启动线程池  
  35.         if (_threadPool instanceof LifeCycle)  
  36.             ((LifeCycle)_threadPool).start();  
  37.     }   
  38.     catch(Throwable e) { mex.add(e);}  
  39.       
  40.     try  {   
  41.         super.doStart();   //这里将会启动handler,说白了就是启动contextHandlerCollection,也是为了启动那些WebAppContext  
  42.     }   
  43.     catch(Throwable e)   
  44.     {   
  45.         Log.warn("Error starting handlers",e);  
  46.     }  
  47.       
  48.     if (_connectors!=null)  {  
  49.         for (int i=0;i<_connectors.length;i++) {  
  50.             try{_connectors[i].start();}  //启动connector  
  51.             catch(Throwable e){  
  52.                 mex.add(e);  
  53.             }  
  54.         }  
  55.     }  
  56.     mex.ifExceptionThrow();  
  57. }  

这里部分虽然看起来代码还挺多的。。不过最主要的就是要干如下的三件事情。。
(1)创建线程池,并且启动

(2)启动内部的handler,其实也就是启动那个contextHandlerCollection,这个handler的启动将会设置WebAppContext的路由设置,以及对WebAppContext的启动。。进而使一些contextListener的启动,servlet的初始化一系列的事情。。

(3)启动connector,它已启动,那么就代表整个server已经开始正常的运行了。。。


另外我们再来看看server对象的一个重要方法吧:

[java] view plaincopy
  1. /* ------------------------------------------------------------ */  
  2. /* Handle a request from a connection. 
  3.  * Called to handle a request on the connection when either the header has been received, 
  4.  * or after the entire request has been received (for short requests of known length). 
  5.  */  
  6. //当connection接收到http请求之后,会调用server的这个方法来处理,例如http头部已经接受完全或者已知长度的http请求全部接受完,例如有contentlength的头部的post请求  
  7. public void handle(HttpConnection connection) throws IOException, ServletException  
  8. {  
  9.     String target=connection.getRequest().getPathInfo();  //获取请求的request的path,例如/manager/hello  
  10.     if (Log.isDebugEnabled()) {  
  11.         Log.debug("REQUEST "+target+" on "+connection);  
  12.         handle(target, connection.getRequest(), connection.getResponse(), Handler.REQUEST);  
  13.         Log.debug("RESPONSE "+target+"  "+connection.getResponse().getStatus());  
  14.     } else {  
  15.         //其实最终还是交给了内部的handler来处理这个请求,而这个handler就是ContextHandlerCollection,  
  16.         //而contextHandlerCollection再将其路由给相应的WebAppContext来处理。。。然后再交给相应的servlet来处理  
  17.         handle(target, connection.getRequest(), connection.getResponse(), Handler.REQUEST);  
  18.     }  
  19. }  

从上面的注释就可以知道,每一个httpConnection当收到了http请求之后都会调用server的这个方法来处理。。而其实这个方法最终又是交给内部的ContextHandlerCollection来处理这个请求。。。

接下来再由ContextHandlerCollection将这个请求路由给对应的WebAppContext,然后再由其路有个内部的servlet来处理。。。


那么到这里为止真个jetty的server的创建和启动就差不多了。。。还是蛮简单的。。。。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值