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