到目前为止,我们已经实现了ServletContext容器,支持Servlet、Filter和Listener组件,支持HttpSession,但是,加载Servlet、Filter和Listener组件时,是写死在服务器里面的IndexServlet、LogFilter和HelloHttpSessionListener这样的类。
而一个正常的Web服务器是从外部加载这些组件的,根据Servlet规范,Web App开发者完成了Servlet、Filter和Listener等组件后,需要按规范把它们打包成.war文件。.war文件本质上就是一个jar包,但它的目录组织如下:
hello-webapp
├── WEB-INF
│ ├── classes
│ │ └── com
│ │ └── example
│ │ ├── filter
│ │ │ └── LogFilter.class
│ │ ├── listener
│ │ │ ├── HelloHttpSessionListener.class
│ │ │ └── HelloServletContextAttributeListener.class
│ │ ├── servlet
│ │ │ ├── HelloServlet.class
│ │ │ └── IndexServlet.class
│ │ └── util
│ │ └── DateUtil.class
│ └── lib
│ ├── logback-classic-1.4.6.jar
│ ├── logback-core-1.4.6.jar
│ └── slf4j-api-2.0.4.jar
├── contact.html
└── favicon.ico
Servlet规范规定,一个.war包解压后,目录/WEB-INF/classes存放所有编译后的.class文件,目录/WEB-INF/lib存放所有依赖的第三方jar包,其他文件可按任意目录存放。
Web服务器通常会提供一个用于访问文件的Servlet,对于以/WEB-INF/开头的路径,Web服务器会拒绝访问,其他路径则按正常文件访问,因此,路径/contact.html可以被访问到,而路径/WEB-INF/contact.html则不能被访问到。注意这个限制是针对浏览器发出的请求的路径限制,如果在Servlet内部读写/WEB-INF/目录下的文件则没有任何限制。利用这个限制,很多MVC框架的模版页通常会存放在/WEB-INF/templates目录下。
以上是关于.war包的目录规范。我们要把写死的Servlet、Filter和Listener组件从服务器项目中摘出来,单独实现一个.war包,然后,我们需要实现服务器启动后动态加载war包,就实现了一个比较完善的Web服务器。