web.xml解析
1 WEB-INF是安全的
我们知道JavaWeb项目的目录结构中存在WEB-INF,而且目录的大小写都是不可忽略的。WEB-INF是客户端不可访问的目录。所以我们可以把一些与配置相关的,不想让客户端浏览器直接访问的东西放到这个目录中。
你可能会说WEB-INF下的东西客户端不能访问,那么要它干什么呢?答案是Servlet可以访问!说白一点,用户访问Servlet,Servlet再去访问WEB-INF下的东西。
WEB-INF目录下必须要有的就是项目的部署描述符文件:web.xml。这个方法由Tomcat在启动时读取到内存,当用户方法某个路径时,通过与
project
jsps ------------------------ 可以自己随意创建目录,只要不在WEB-INF目录下客户端就可以访问。
a.jsp -------------------- 客户端可以访问 WEB-INF ------------------ 无法直接访问
b.jsp -------------------- 客户端不能直接访问,但可以通过Servlet间接方法。 web.xml --------------- 项目部署描述符 lib ----------------------- 项目所需Jar包 classes ----------------- 项目所有class文件 index.jsp ----------------- 客户端可以访问
2
http://localhost/hello/jsps/a.jsp,这说明你的上下文目录中存在jsps目录,并且在jsps目录下存在a.jsp文件。我们已经测试过了,没有问题!
但如果我们要让Servlet来处理客户发出的请求呢?难道我们让用户在浏览器的地址栏中输入要访问的class文件路径么:http://localhost/hello/WEB-INF/classes/cn.itcast.MyServlet.class?呵呵~,这当前是不行的。为了可以让Servlet处理请求,需要把Servlet部署到web.xml文件中,最终Servlet对应一个(或多个)路径!这就是
3
通配符就是“*”,表示任意路径。但是,使用通配符也是有一定的限制的! ? *.xxx格式:*.do、*.action、*.html; ? /xxx/*格式:/do/*、/action/*; 如果通配符前面存在限定路径,那么通配符后面就不能用扩展名。例如:/*、/a/*、/a/b/c/*都是正确的。
如果通配符后面有扩展名,那么通配符前面就不能有限定路径。例如:*do、*.action、*.html都是正确的。
设当前上下文为:http://localhost/day07_01
4
? 通配符不能单独出现:
? 通配符不能即有限定路径,又有扩展名:
误的。
? 通配符不能出现在路径中间位置:
误的。
5
当用户访问了不存在的路径后,就会执行NotFoundSourceServlet的service()方法!
5 Tomcat已设置的
在êTALINA_HOME%\\conf\\web.xml文件中,Tomcat为我们提供了一些默认配置信息:两个Servlet的配置、session的超时设置,还有N多个MIME类型。
如果我们在自己的项目中也配置了相同的
Servlet线程不安全
1 Servlet是单例的
每个类型的Servlet只会被创建一次,创建之后就会被放到缓存池中,以后就直接使用缓存池中的Servlet,不会再去创建了。
可能你会想,Servlet是我们自己写的,我们如果给Servlet留下了public构造器,那么Servlet就不是单例了。
但是,Servlet的整个生命周期都不由我们来管理,而是由Tomcat来全全负责。Servlet的创建,以及调用都是由Tomcat来完成。
2 Servlet是线程不安全的
Tomcat是多线程的,也就是说可能会同时有多个用户向Tomcat服务器发出请求,Tomcat会为每个请求开辟一个线程。
如果同时有多个请求,请求的是同一个Servlet,那么Servlet就会存在线程安全问题!!!当然,如果请求的不是同一个Servlet就不会出现线程安全问题了。但是我们已经知道Servlet是单例的,每种类型的Servlet只会有一个实例对象,所以就会出现线程安全问题。
3 能声明为局部变量,就不要声明为属性
处理线程安全的办法我们在学习基础的时候已经很清楚了。你可以在doGet()或doPost()方法中添加synchronized块,也可以把doGet()或doPost()声明为synchronized方法。但是,如果是这样,那么一定会很慢,因为synchronized会让多个线程“排队”。所以,这不是最佳选择!
局部变量不会被多个线程共享,所以可以声明为局部变量就一定不要声明为属性。 public class MyServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) { A a = new A(); a.fun(); } } public class MyServlet extends HttpServlet { private A a = new A(); public void doPost(HttpServletRequest req, HttpServletResponse res) { a.fun(); } } 如果可以把A声明为局部变量,那么就不要声明为属性。我们来分析一下,当A是局部变量时,doPost()方法被调用一次,那么就会执行一次A a = new A()语句,也就是说,每次调用都会使用新的a对象;如果把A声明为属性,那么private A a = new A()就是显示初始化语句了,显示初始化语句只有在对象被创建时才会被调用,而在调用对象的方法时就不会再次调用了,那么无论调用多少次a.fun(),最终都是在使用同一个a对象。
这就是为什么属性会有线程安全问题,而局部变量不会的原因了!