前面的文章已经提到过,在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的源码过程还算蛮顺利的。。。莫非源码看多了。。。以后读源码也越来越顺利了。。。