<


1.new WebAppContext()


    1.1    private MetaData _metadata=new MetaData();



    1.2 调用构造方法


        ServletContextHandler(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)

            初始化    ContextHandler._scontext = new Context();

            设置    _sessionHandler        即使为空

            设置    _securityHandler    即使为空

            设置    _servletHandler        即使为空

2、经server._handler._beans.start调用   – >WebAppContext(AbstractLifeCycle).start()

    2.1    WebAppContext._metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());

    2.2    WebAppContext.doStart()

    2.2.1    WebAppContext.preConfigure()            //预先配置


    2.2.1.1    WebAppContext.loadConfigurations    //加载配置信息-》



                    用sun.misc.Launcher$AppClassLoader的类加载器预先加载储存于dftConfigurationClasses的class信息,并且初始化到_configurations[i]中



                    _configurations[i]=(Configuration)Loader.loadClass(this.getClass(), _configurationClasses[i]).newInstance();



                    这些类包括:



                    ”org.eclipse.jetty.webapp.WebInfConfiguration”        WEBINFO文件解压等处理



                    ”org.eclipse.jetty.webapp.WebXmlConfiguration”        WebXml配置文件读取



                    ”org.eclipse.jetty.webapp.MetaInfConfiguration”        根据webxml生成filter,servlet等对象



                    ”org.eclipse.jetty.webapp.FragmentConfiguration”        未知,但似乎没什么用    



                    ”org.eclipse.jetty.webapp.JettyWebXmlConfiguration”    未知,但似乎某种情况下会起到什么用处



    2.2.1.2    WebAppContext.loadSystemClasses    //加载系统类



                    设置private ClasspathPattern _systemClasses = new ClasspathPattern(dftSystemClasses);



                    而dftSystemClasses=



                    public final static String[] dftSystemClasses =

{

        “java.”,                            // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)

        “javax.”,                           // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)

        “org.xml.”,                         // needed by javax.xml

        “org.w3c.”,                         // needed by javax.xml

        “org.apache.commons.logging.”,      // TODO: review if special case still needed

        “org.eclipse.jetty.continuation.”,  // webapp cannot change continuation classes

        “org.eclipse.jetty.jndi.”,          // webapp cannot change naming classes

        “org.eclipse.jetty.plus.jaas.”,     // webapp cannot change jaas classes

        “org.eclipse.jetty.websocket.WebSocket”, // WebSocket is a jetty extension

        “org.eclipse.jetty.websocket.WebSocketFactory”, // WebSocket is a jetty extension

        “org.eclipse.jetty.websocket.WebSocketServlet”, // webapp cannot change WebSocketServlet

        “org.eclipse.jetty.servlet.DefaultServlet” // webapp cannot change default servlets

    } ;



    2.2.1.3    WebAppContext.loadServerClasses()    //加载服务类



                   设置private ClasspathPattern _serverClasses = new ClasspathPattern(dftServerClasses);



                    而dftServerClasses=



public final static String[] dftServerClasses =

    {

        “-org.eclipse.jetty.continuation.”, // don’t hide continuation classes

        “-org.eclipse.jetty.jndi.”,         // don’t hide naming classes

        “-org.eclipse.jetty.plus.jaas.”,    // don’t hide jaas classes

        “-org.eclipse.jetty.websocket.WebSocket”, // WebSocket is a jetty extension

        “-org.eclipse.jetty.websocket.WebSocketFactory”, // WebSocket is a jetty extension

        “-org.eclipse.jetty.websocket.WebSocketServlet”, // don’t hide WebSocketServlet

        “-org.eclipse.jetty.servlet.DefaultServlet”, // don’t hide default servlet

        “-org.eclipse.jetty.servlet.listener.”, // don’t hide useful listeners

        “org.eclipse.jetty.”                // hide other jetty classes

    } ;



    2.2.1.4    创建WebAppClassLoader WebAppClassLoader classLoader = new WebAppClassLoader(this);



    2.2.1.4.1    按照如下构造参数顺序构造URLClassLoader



                            WebAppClassLoader构造参数中的parent->Classloader



                            Thread.currentThread().getContextClassLoader()



                            WebAppClassLoader.class.getClassLoader()



                            ClassLoader.getSystemClassLoader()



    2.2.1.5    WebAppContext.preConfigure().        最后一步    configurations[i].preConfigure(this);调用2.2.1.1生成的对象中的preConfigure方法



    2.2.1.5.1    WebInfConfiguration.findWorkDirectory()        查找context是否已经设置了webINF的参数



                    //如果有,就直接使用



    2.2.1.5.2    WebInfConfiguration.resolveTempDirectory().makeTempDirectory        //在用户的个人临时文件夹目录创建文件夹    new File(System.getProperty(“java.io.tmpdir”))           



                    context.setTempDirectory(tmpDir);



                    文件夹的创建规则,可以参考    resolveTempDirectory方法的文档



                    A. Try to use an explicit directory specifically for this webapp:






  1.  Iff an explicit directory is set for this webapp, use it. Do NOT set delete
    on exit.


  2. Iff javax.servlet.context.tempdir context attribute is set for this webapp
    && exists && writeable, then use it. Do NOT set delete on exit.





                    B. Create a directory based on global settings. The new directory will be
called “Jetty“+host+”“+port+”__”+context+”“+virtualhost Work out where to
create this directory:






  1. Iff $(jetty.home)/work exists create the directory there. Do NOT set delete
    on exit. Do NOT delete contents if dir already exists.


  2. Iff WEB-INF/work exists create the directory there. Do NOT set delete on
    exit. Do NOT delete contents if dir already exists.


  3. Else create dir in $(java.io.tmpdir). Set delete on exit. Delete contents if
    dir already exists.













    2.2.1.5.3    WebInfConfiguration.unpack (context);



    2.2.1.5.3.1                    web_app = context.newResource(war);               



    2.2.1.5.3.1.1                       return  Resource.newResource(urlOrPath);          URL = file.toURI().toURL()        file:/E:/webapp.war        返回了一个FileResources



    2.2.1.5.3.2                    Resource jarWebApp = JarResource.newJarResource(web_app);    将FileResources转化为一个jarsource        采用方式为将file:/E:/webapp.war修改为jar:file:/E:/webapp.war~/



    2.2.1.5.3.3        context.getTempDirectory(), “.extractlock”位置生成一个控制锁



    2.2.1.5.3.4        extractedWebAppDir.mkdir();        extractedWebAppDir即为临时文件夹



                            例如C:\Documents and Settings\Administrator\Local Settings\Temp\jetty-0.0.0.0-8080-webapp.war--any-\webapp



    2.2.1.5.3.5        jar_web_app.copyTo(extractedWebAppDir);    jar资源,即war包进行解,拷贝到extractedWebAppDir即临时目录中



    2.2.1.5.3.6        删除控制锁context.getTempDirectory(), “.extract_lock”



    2.2.1.5.3.7        context.setBaseResource(web_app);        设置context的基础资源位置是刚才申请的临时文件夹



    2.2.1.5.4            对父类的container进行处理    把父类依赖的jar包加入当前的上下文classloader中    //Apply ordering to container jars - if no pattern is specified, we won’t match any of the container jars



                            最终执行的方法context.getMetaData().addContainerJar(Resource.newResource(uri));



    2.2.1.5.5            对WEBINF的jar包进行处理



                            最终执行的方法context.getMetaData().addWebInfJar(Resource.newResource(uri));



    2.2.1.5.5.1            List<Resource> jars = findJars(context);    获取到web-inf/lib目录下的所有jar包



                            调用2.2.1.5.5执行webInfJarNameMatcher.match(webInfPattern, uris, true)



                            最终调用context.getMetaData().addWebInfJar(Resource.newResource(uri));,将web-inf/lib下的jar包或者zip包加入classpath







    2.2.1.5.6    WebXmlConfiguration.preConfigure    预处理webxml



    2.2.1.5.6.1    String defaultsDescriptor = context.getDefaultsDescriptor();    解析    webdefault.xml    org/eclipse/jetty/webapp/webdefault.xml



    2.2.1.5.6.2    context.getMetaData().setDefaults (dftResource);    给MetaData设置webdefault.xml配置



    2.2.1.5.6.2.1    MetaData._webDefaultsRoot =  new DefaultsDescriptor(webDefaults); 



    2.2.1.5.6.2.1.1    _webDefaultsRoot.parse();        解析webdefault.xml



    2.2.1.5.6.2.1.1.1    webDescriptor.newParse()        新建一个XmlParser xmlParser=new XmlParser()    底层为SAXParserFactory



    2.2.1.5.6.2.1.1.2    在xmlParse中注册dtd和URL的关系



    2.2.1.5.6.2.1.1.3    webDescriptor._root = _parser.parse(_xml.getInputStream())        将webdefault.xml解析为一个Node对象



    2.2.1.5.6.2.1.1.4    webDescriptor.processVersion    ,解析webdefault.xml中的版本号、metadata-complete(是否启用注解)



    2.2.1.5.6.2.1.1.5    webDescriptor.processOrdering    解析如下参数



                                absolute-ordering    是否WebFragment要排序



    2.2.1.5.6.3    Resource webxml = findWebXml(context);        寻找web.xml,解析,但是不执行



    2.2.1.5.6.4    //parse but don’t process override-web.xml     



 



    2.2.1.5.7    MetaInfConfiguration.preConfigure    预处理MetaINF



    2.2.1.5.7.1    //Merge all container and webinf lib jars to look for META-INF resources    将所有ContainerJars和WEBINF jars进行合并



    2.2.1.5.7.2    JarScanner scanner新建jar包扫描类



    2.2.1.5.7.3    scanner扫描WEBINF下的文件,如果是:web-fragment.xml和META-INF/resources/或者以DTD结尾,则分别加载到



                        addResource(context,METAINF_FRAGMENTS,Resource.newResource(jarUri));



                        addResource(context,METAINF_RESOURCES,Resource.newResource(“jar:”+jarUri+”!/META-INF/resources”));

                        addResource(context,METAINF_TLDS,Resource.newResource(“jar:”+jarUri+”!/“+name));



                        中



    2.2.1.5.8    FragmentConfiguration.preConfigure    预处理Fragment



    2.2.1.5.8.1    findWebFragments(context, context.getMetaData());,最终完成的是



                    metaData.addFragment(frag, Resource.newResource(frag.getURL()+”/META-INF/web-fragment.xml”));    



                    metaData.addFragment(frag, Resource.newResource(“jar:”+frag.getURL()+”!/META-INF/web-fragment.xml”));



   



    2.2.1.5.9    JettyWebXmlConfiguration.preConfigure    预处理jetty的webxml        空



                    



    2.2.1.6    WebAppContext.super.doStart()        ContextHandler.doStart()    



    2.2.1.6.1    设置当前线程的类加载器为WebAppClassLoader



    2.2.1.6.2    设置 contexthandler._mimeTypes = new MimeTypes()



    2.2.1.6.3    设置当前线程的线程局部变量context.set(_scontext);



    2.2.1.6.4    调用startContext方法,即调用WebAppContext.startContext()



    2.2.1.6.4.1    WebAppContext.configure()



    2.2.1.6.4.2    调用2.2.1.1五个变量的configure方法



        



                    ”org.eclipse.jetty.webapp.WebInfConfiguration”        WEBINFO文件解压等处理



                    ”org.eclipse.jetty.webapp.WebXmlConfiguration”        WebXml配置文件读取



                    ”org.eclipse.jetty.webapp.MetaInfConfiguration”        根据webxml生成filter,servlet等对象



                    ”org.eclipse.jetty.webapp.FragmentConfiguration”        未知,但似乎没什么用    



                    ”org.eclipse.jetty.webapp.JettyWebXmlConfiguration”    未知,但似乎某种情况下会起到什么用处







    2.2.1.6.4.2.1     WebInfConfiguration.configure



    2.2.1.6.4.2.1.1    ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);    将/WEB-INF/classes增加到classpath中    最终增加到了URLClassLoader中的    private final URLClassPath ucp;上



    2.2.1.6.4.2.1.2    ((WebAppClassLoader)context.getClassLoader()).addJars(lib);                将/WEB-INF/lib中的jar包或者zip包增加到classpath中,    最终增加到了URLClassLoader中的    private final URLClassPath ucp;上



    2.2.1.6.4.2.1.3    Look for extra resource        查找扩展资源



   



    2.2.1.6.4.2.2    WebXmlConfiguration.configure



    2.2.1.6.4.2.2.1    context.getMetaData().addDescriptorProcessor(new StandardDescriptorProcessor());    为MetaData增加webxml描述的处理器,是StandardDescriptorProcessor



    2.2.1.6.4.2.2.2    new StandardDescriptorProcessor()时,需要注册一系列解析器



                    registerVisitor(“context-param”, this.getClass().getDeclaredMethod(“visitContextParam”, signature));

                    registerVisitor(“display-name”, this.getClass().getDeclaredMethod(“visitDisplayName”, signature));

                    registerVisitor(“servlet”, this.getClass().getDeclaredMethod(“visitServlet”, 
signature));

                    registerVisitor(“servlet-mapping”, this.getClass().getDeclaredMethod(“visitServletMapping”,  signature));

                    registerVisitor(“session-config”, this.getClass().getDeclaredMethod(“visitSessionConfig”, 
signature));

                    registerVisitor(“mime-mapping”, this.getClass().getDeclaredMethod(“visitMimeMapping”,  signature));

                    registerVisitor(“welcome-file-list”, this.getClass().getDeclaredMethod(“visitWelcomeFileList”, 
signature));

                    registerVisitor(“locale-encoding-mapping-list”, this.getClass().getDeclaredMethod(“visitLocaleEncodingList”,  signature));

                    registerVisitor(“error-page”, this.getClass().getDeclaredMethod(“visitErrorPage”, 
signature));

                    registerVisitor(“taglib”, this.getClass().getDeclaredMethod(“visitTagLib”,  signature));

                    registerVisitor(“jsp-config”, this.getClass().getDeclaredMethod(“visitJspConfig”, 
signature));

                    registerVisitor(“security-constraint”, this.getClass().getDeclaredMethod(“visitSecurityConstraint”,  signature));

                    registerVisitor(“login-config”, this.getClass().getDeclaredMethod(“visitLoginConfig”, 
signature));

                    registerVisitor(“security-role”, this.getClass().getDeclaredMethod(“visitSecurityRole”,  signature));

                    registerVisitor(“filter”, this.getClass().getDeclaredMethod(“visitFilter”, 
signature));

                    registerVisitor(“filter-mapping”, this.getClass().getDeclaredMethod(“visitFilterMapping”,  signature));

                    registerVisitor(“listener”, this.getClass().getDeclaredMethod(“visitListener”, 
signature));

                    registerVisitor(“distributable”, this.getClass().getDeclaredMethod(“visitDistributable”,  __signature));



                    这些解析器,既是web.xml的解析处理器



    2.2.1.6.4.2.3     MetaInfConfiguration.configure        空



    2.2.1.6.4.2.4     FragmentConfiguration.configure    



    2.2.1.6.4.2.4.1    context.getMetaData().orderFragments()    对Servlet3.0片段Fragment进行排序           



                                    —-需要看protected Ordering _ordering是否有值;



                                    —-如果没有值,则只执行_orderedWebInfJars.addAll(_webInfJars);方法,将webINF的jar全部放到_orderedWebInfJars中  







    2.2.1.6.4.2.5    JettyWebXmlConfiguration.configure



    2.2.1.6.4.2.5.1    在web-inf下寻找jetty8-web.xml,否则寻找web-jetty.xml,



                                XmlConfiguration jetty_config = (XmlConfiguration)context.getAttribute(XML_CONFIGURATION);



                               寻找到之后,调用jetty_config.configure(context);进行解析



    2.2.1.6.4.3    WebAppContext._metadata.resolve(this);    对webAppContext进行解析处理



    2.2.1.6.4.3.1    _origins.clear();



    2.2.1.6.4.3.2    // set the webxml version    给context.getServletContext()设置版本号,即给_scontext设置版本号



    2.2.1.6.4.3.3    执行StandardDescriptorProcessor    p



    2.2.1.6.4.3.3.1    p.process(context,getWebDefault());    解析webdefault.xml    使用StandardDescriptorProcessor解析webdefault.xml中的标签

    2.2.1.6.4.3.3.2    p.process(context,getWebXml())            解析web.xml            使用StandardDescriptorProcessor解析web.xml中的标签



                        举例说明,servlet加载过程:    参见StandardDescriptorProcessor.protected void visitServlet(WebAppContext context, Descriptor descriptor, XmlParser.Node node)方法



                        1、获取ID



                        2、获取servlet-name



                        3、创建ServletHolder,设置servletName为 servlet-name



                        4、将ServletHolder设置入Context中的ServletHandler            org.eclipse.jetty.servlet.ServletHandler    在步骤1.2或者首次调用getServletHandler时创建

                        5、解析init-param    并设置入ServletHolder



                        6、解析servlet-class



                        7、如果servlet-class是jspservlet,则设置初始化参数scratchdir



                        8、如果servlet-class不为空,则



                        8.1    ((WebDescriptor)descriptor).addClassName(servlet_class);        在WebDescriptor中增加一条记录



                        8.2    Origin o = context.getMetaData().getOrigin(servlet_name+”.servlet.servlet-class”);    尝试从缓存中获取servlet_name+”.servlet.servlet-class”



                                如果获取不到,则holder.setClassName(servlet_class);

                                                        context.getMetaData().setOrigin(servlet_name+”.servlet.servlet-class”, descriptor);



                        9、加载load-on-startup参数



                        10、加载security-role-ref参数



                        11、加载run-as参数



                        12、加载async-supported参数



                        13、加载enabled参数



                        14、加载multipart-config参数



    2.2.1.6.4.3.3.3    p.process(context,wd);    解析WebDescriptor      getOverrideWebs()



   



    2.2.1.6.4.4    WebAppContext.super.startContext()        加载父类的startContext



    2.2.1.6.4.4.1    将SessionHandler,SecurityHandler,ServletHandler组成管道队列



    2.2.1.6.4.4.2    将sessionHandler作为第一个管道,设置入WebAppContext(handlerWrapper._handler)



    2.2.1.6.4.4.3    WebAppContext(ServletContextHandler)super.startContext()



    2.2.1.6.4.4.4    WebAppContext().super.doStart()->scopeHandler.dostart()->scopeHandler.doStart()—->>>>>>>>>>…….



    2.2.1.6.4.4.4.1    sessionhandler.start()



    2.2.1.6.4.4.4.2    ConstraintSecurityHandler.start()



    2.2.1.6.4.4.4.3    ServletHandler.start()



    2.2.1.6.4.4.4.3.1    updateNameMappings()    更新_servletNameMap和_servlets数组



    2.2.1.6.4.4.4.3.2    updateMappings()    更新_filterPathMappings和_filterNameMappings,_servletPathMap,



  



    2.2.1.6.4.4.5    WebAppContext(ContextHandler)._errorHandler.start();



    2.2.1.6.4.4.6    callContextInitialized(((ServletContextListener)LazyList.get(_contextListeners, i)), event);    通知监听事件



   



    2.2.1.6.4.4.7    结束    2.2.1.6.4.4.3    WebAppContext(ServletContextHandler)super.startContext()



    2.2.1.6.4.4.8    OK to Initialize servlet handler now                    ServletContextHandler.startContext  –>  _servletHandler.initialize()



    2.2.1.6.4.4.8.1    _filters.start()    



    2.2.1.6.4.4.8.2    servlets[i].start()    ServletHolder.start



    2.2.1.6.4.4.8.2.1    ServletHolder -> Holder -> Holder._class=Loader.loadClass(Holder.class, _className);     加载class类


    2.2.1.6.4.4.8.2.2    checkServletType();    检查servlet类型   


    2.2.1.6.4.4.8.2.3    initServlet();    包括实例化,调用初始化方法等



                     _servlet=newInstance();   



                    _config=new Config();



                    _servlet.init(_config);



    2.2.1.6.5    结束2.2.1.6.4 WebContext.startContext()



    2.2.1.6.6    current_thread.setContextClassLoader(old_classloader);将classloader恢复原样



   



    2.2.1.7    WebAppContext.postConfigure() 



            WebInfConfiguration.postConfigure 空



            WebXmlConfiguration.postConfigure空



            MetaInfConfiguration.postConfigure空



            FragmentConfiguration.postConfigure空



            JettyWebXmlConfiguration.postConfigure空







  —————————至此webAppContext启动完毕











作为Handler的运行过程如下,Servlet对象将请求交给webAppContext执行handler方法,WebAppContext含有三个handler链,顺序为sessionhandler,ConstraintSecurityHandler,ServletHandler



由于sessionhandler和ServletHandler是scopeHandler,而ConstraintSecurityHandler是普通Handler,因此执行顺序如下

    3.1    sessionhandler.doScope()     创建session,对 cookie写出jsessionid



    3.2    ServletHandler.doScope()     根据target,从_servletNameMap中获取到一个ServletHolder    servlet_holder=
(ServletHolder)_servletNameMap.get(target);

                                                    设置到baseRequest.setUserIdentityScope(servlet_holder)中



    3.3    sessionhandler.doHandler()    空,正常后延



    3.4    ConstraintSecurityHandler.doHandler()    未知代码



    3.5    ServletHandler.doHandler()



            ServletHolder servlet_holder=(ServletHolder) baseRequest.getUserIdentityScope();    公益企业ServletHolder



            FilterChain    获取过滤器链



            执行过滤器链



            如果过滤器链执行完毕,执行servlet_holder.handle(baseRequest,req,res);



            即:servlet.service(request,response);







———————————至此WebAppContext运行完毕







以上就是花三天时间整理的jetty-webAppContext运行过程



———–



对于我自己,要把代码忘掉,记住核心的部分。记得太多反而没用。



比如WebAppContext,最核心的部分应该是WebAppClassLoader类对不同的应用环境进行隔离的部分:



    通过类加载器实现了不同应用在同一个进程内的妥善隔离,值得学习。这是一种非常有效的沙盒机制。







还有web.xml的解析部分,通过反射机制实现了每个标签的处理程序







但其中糟粕的地方也挺多,例如WebAppClassLoader被设置到了ThreadLocal变量中,这样意味着:服务器启动只能用单线程启动,否则就会异常。



虽然并没什么太大影响,但是仍然不太建议这么做。