jetty之WebAppContext

前面的文章已经提到过,在servlet容器中,每一个webapplication都对应一个contextHandler,但是前面讲到的contextHandler的定义主要是实现了将http的请求进行路由,将其交给sessionHandler,然后再交给servletHandle然后转交给对应的servlet的来进行处理。。。

这里的WebAppContext是对其的一种补充,完善了webapp的启动和handler的管理。。。

先来看它的继承体系吧:



其实着了也可以看到它是对ContextHandler的一种扩展。。那么先来看看Context的定义吧,先来看看他的一些属性的定义:

    protected SecurityHandler _securityHandler;  //安全handler
    protected ServletHandler _servletHandler;  //servlethandler,其用于将http请求路由给相应的servlet来处理
    protected SessionHandler _sessionHandler;   //sessionhandler,其会对servlethandler进行一层包装

这里定义了3个handler,每个是什么用基本上看名字就已经看出来了。。。

servletHandler是用于将http请求交给对应的servlet来处理。。。sessionHandler则是对servletHandler进行了一层包装(装饰器模式),用于一些session的预处理什么的。。。

接下来再来看看它的一些重要的方法定义:

    //添加servlet,这里将servlet的className与path对应起来。。。
    public ServletHolder addServlet(String className,String pathSpec)
    {
        return _servletHandler.addServletWithMapping(className, pathSpec);
    }

    //将servlet的类型与path对象起来
    public ServletHolder addServlet(Class servlet,String pathSpec)
    {
        return _servletHandler.addServletWithMapping(servlet.getName(), pathSpec);
    }
    
    //将servlet的holder与path对应起来。。
    public void addServlet(ServletHolder servlet,String pathSpec)
    {
        _servletHandler.addServletWithMapping(servlet, pathSpec);
    }

    //添加filter
    public void addFilter(FilterHolder holder,String pathSpec,int dispatches)
    {
        _servletHandler.addFilterWithMapping(holder,pathSpec,dispatches);
    }

    public FilterHolder addFilter(Class filterClass,String pathSpec,int dispatches)
    {
        return _servletHandler.addFilterWithMapping(filterClass,pathSpec,dispatches);
    }

    public FilterHolder addFilter(String filterClass,String pathSpec,int dispatches)
    {
        return _servletHandler.addFilterWithMapping(filterClass,pathSpec,dispatches);
    }
    

这些方法就是用于在当前的context环境中添加servlet以及filter的。。。。这里也可以看出其实它是交给servletHandler来处理的。。这里也就知道servletHandler的重要作用了吧。。。

    //这里主要是初始化servletHandler
    protected void startContext() throws Exception
    {
        super.startContext();
        
        // OK to Initialize servlet handler now
        if (_servletHandler != null && _servletHandler.isStarted())
            _servletHandler.initialize();
    }

这个方法用于启动context,它会在当前WebAppContext的doStart之中被调用,这里主要干的事情就是对servletHnandler进行初始化。。。


接下来我们来看WebAppContext的定义吧,这里就先不详细的看他的定义吧,因为以后webApp的创建和启动的时候会着重分析它。。。因为它封装了很多创建和启动的代码。。。来看看它的doStart方法:

    //这里可以理解为启动这个app,app都需要创建自己的classLoader
    protected void doStart() throws Exception {
        try {
            loadConfigurations();  //加载器
            
            	//设置他们的context
            for (int i=0;i<_configurations.length;i++) {
                _configurations[i].setWebAppContext(this);
            }

            // Configure classloader
            _ownClassLoader=false;
            if (getClassLoader()==null) {
                WebAppClassLoader classLoader = new WebAppClassLoader(this);  //创建classLoader
                setClassLoader(classLoader);  //设置当前的classLoader
                _ownClassLoader=true;
            }

            if (Log.isDebugEnabled()) 
            {
                ClassLoader loader = getClassLoader();
                Log.debug("Thread Context class loader is: " + loader);
                loader=loader.getParent();
                while(loader!=null)
                {
                    Log.debug("Parent class loader is: " + loader); 
                    loader=loader.getParent();
                }
            }
            //这个里面的操作会加压war文件
            for (int i=0;i<_configurations.length;i++) {
                _configurations[i].configureClassLoader();
            }
            getTempDirectory();
            
            super.doStart();

            if (isLogUrlOnStart()) 
                dumpUrl();
        }
        catch (Exception e)
        {
            //start up of the webapp context failed, make sure it is not started
            Log.warn("Failed startup of context "+this, e);
            _unavailableException=e;
            _unavailable = true;
        }
    }

这里主要是设置了当前的classLoader,然后还对一些配置对象进行了设置,然后让这些初始配置对象进行初始化。。。

他们都有如下:

    //一些默认的配置类,每一个配置类都有其要干的事情,都还挺重要的
    private static String[] __dftConfigurationClasses =  
    { 
        "org.mortbay.jetty.webapp.WebInfConfiguration",   //对webinfo的处理,主要用于载入class文件以及jar包
        "org.mortbay.jetty.webapp.WebXmlConfiguration",    //这个主要是对web.xml的处理
        "org.mortbay.jetty.webapp.JettyWebXmlConfiguration",
        "org.mortbay.jetty.webapp.TagLibConfiguration" 
    } ;

另外来看一个方法:

    //相当于解压war包
    protected void resolveWebApp() throws IOException
    {
        Resource web_app = super.getBaseResource();
        if (web_app == null)
        {
            if (_war==null || _war.length()==0) {
                _war=getResourceBase();
            }
            
            // Set dir or WAR  设置war的路径,相当于准备读war包了
            web_app= Resource.newResource(_war);  

            // Accept aliases for WAR files
            if (web_app.getAlias() != null) {
                Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
                web_app= Resource.newResource(web_app.getAlias());
            }

            if (Log.isDebugEnabled())
                Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());

            //这里将原来的war包包装为jar资源
            if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
            {
                // No - then lets see if it can be turned into a jar URL.
                Resource jarWebApp= Resource.newResource("jar:" + web_app + "!/");   //类似于jar:file:/F:/360云盘/jettywork/jetty/webapps/manager.war!/
                if (jarWebApp.exists() && jarWebApp.isDirectory())
                {
                    web_app= jarWebApp;
                    _war= web_app.toString();
                }
            }

            // If we should extract or the URL is still not usable
            if (web_app.exists()  && (
               (_copyDir && web_app.getFile()!= null && web_app.getFile().isDirectory()) 
               ||
               (_extractWAR && web_app.getFile()!= null && !web_app.getFile().isDirectory())
               ||
               (_extractWAR && web_app.getFile() == null)
               ||
               !web_app.isDirectory()
               ))
            {
                // Then extract it if necessary.
            	//获取解压的路径,解压之后将会放到这个地方
                File extractedWebAppDir= new File(getTempDirectory(), "webapp");
                
                //如果app是文件夹的话,那么直接复制就好了
                if (web_app.getFile()!=null && web_app.getFile().isDirectory())
                {
                    // Copy directory
                    Log.info("Copy " + web_app.getFile() + " to " + extractedWebAppDir);
                    IO.copyDir(web_app.getFile(),extractedWebAppDir);
                }
                else
                {
                	//先要判断放app的路径是否已经存在
                    if (!extractedWebAppDir.exists())  {  
                        //it hasn't been extracted before so extract it
                        extractedWebAppDir.mkdir();  //创建临时文件夹
                        Log.info("Extract " + _war + " to " + extractedWebAppDir);
                        JarResource.extract(web_app, extractedWebAppDir, false);   //解压
                    }
                    else
                    {
                        //only extract if the war file is newer
                        if (web_app.lastModified() > extractedWebAppDir.lastModified())
                        {
                            extractedWebAppDir.delete();
                            extractedWebAppDir.mkdir();
                            Log.info("Extract " + _war + " to " + extractedWebAppDir);
                            JarResource.extract(web_app, extractedWebAppDir, false);
                        }
                    }
                }
                //这里相当于将web_app的值指向已经解压后的路径
                web_app= Resource.newResource(extractedWebAppDir.getCanonicalPath());

            }

            // Now do we have something usable?
            if (!web_app.exists() || !web_app.isDirectory())
            {
                Log.warn("Web application not found " + _war);
                throw new java.io.FileNotFoundException(_war);
            }

            if (Log.isDebugEnabled())
                Log.debug("webapp=" + web_app);

            // ResourcePath
            super.setBaseResource(web_app);  //设置部署的文件夹的路径
        }
    }
    

这个就是对当前的web程序的war包进行处理,进行解压,放到相应的文件夹下面等等。。。


好了,其实到这里,对整个webApp的启动和创建已经设计都有了基本的了解了。。。


看jetty的源码过程还算蛮顺利的。。。莫非源码看多了。。。以后读源码也越来越顺利了。。。?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值