1、Servlet开发过程及执行过程
2、Servlet路径映射
3、缺省Servlet
4、Servlet生命周期
5、Servlet自动加载
6、Servlet线程安全
Servlet开发过程及执行过程
1、编写java类,继承HttpServlet 2、重写doGet和doPost方法 3、Servlet程序交给tomcat服务器运行 4、在web.xml文件中进行配置
<!-- 配置一个servlet --> <!-- servlet的配置 --> <servlet> <!-- servlet的内部名称,自定义,尽量有意义 --> <servlet-name>FirstServlet</servlet-name> <!-- servlet的类全名: 包名 + 简单类名 --> <servlet-class>ysdrzp.servlet.FirstServlet</servlet-class> </servlet> <!-- servlet的映射配置 --> <servlet-mapping> <!-- servlet的内部名称,一定要和上面的内部名称保持一致 --> <servlet-name>FirstServlet</servlet-name> <!-- servlet的映射路径(访问servlet的名称) --> <url-pattern>/first</url-pattern> </servlet-mapping>
public class FirstServlet extends HttpServlet { /** * * @param request * @param response * @throws ServletException * @throws IOException */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write("this is first servlet"); } /** * * @param request * @param response * @throws ServletException * @throws IOException */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
访问http://localhost:8080/myweb/first是如何找到FirstServlet的?
首先tomcat服务器启动时会加载webapps中的每个web应用的web.xml配置文件。
http://指定http协议,localhost会到本地的hosts文件中查找是否存在该域名对应的IP地址127.0.0.1,根据8080端口找到tomcat服务器,
/myweb会在tomcat的webapps目录下找myweb的目录,/first 匹配资源名称。
1)在myweb的web.xml中查找是否有匹配的url-pattern的内容(/first)
2)如果找到匹配的url-pattern,则使用当前servlet-name的名称到web.xml文件中查询是否相同名称的servlet配置
3)如果找到,则取出对应的servlet配置信息中的servlet-class内容:ysdrzp.servlet.FirstServlet
4)通过反射:构造FirstServlet的对象,然后调用FirstServlet里面的方法
Servlet路径映射
精确映射
/first http://localhost:8080/myweb/first
/xxx/firstServlet http://localhost:8080/myweb/xxx/firstServlet
模糊匹配
/* http://localhost:8080/myweb/任意路径
/test/* http://localhost:8080/myweb/test/任意路径
*.后缀名 http://localhost:8080/myweb/任意路径.do 如:*.do *.action *.html(伪静态)
假如将上面的配置文件,映射信息调整一下由<url-pattern>/first</url-pattern>改为<url-pattern>/*</url-pattern>
在浏览器地址栏中输入http://localhost:8080/myweb/xxxx(任意的请求映射路径/xxxx)一样可以请求到FirstServlet。
注意:
1)url-pattern(请求servlet的映射路径)要么以 / 开头,要么以*开头
2)不能同时使用两种模糊匹配,例如 /test/*.do是非法路径
3)当有输入的URL有多个servlet同时被匹配的情况下:3.1 精确匹配优优先,长的最像优先被匹配 3.2 以后缀名结尾的模糊url-pattern优先级最低
缺省Servlet路径
Servlet的缺省路径(<url-pattern>/</url-pattern>)是在tomcat服务器内置的一个路径。该路径对应的是一个DefaultServlet(缺省Servlet)。这个缺省的Servlet的作用是用于解析web应用的静态资源文件。
URL输入http://localhost:8080/myweb/index.html 是如何读取文件?
1)到当前myweb应用下的web.xml文件查找是否有匹配的url-pattern。
2)如果没有匹配的url-pattern,则交给tomcat的内置的DefaultServlet处理
3)DefaultServlet程序到myweb应用的根目录下查找是存在一个名称为index.html的静态文件。
4)如果找到该文件,则读取该文件内容,返回给浏览器。
5)如果找不到该文件,则返回404错误页面。
结论: 先找动态资源,再找静态资源。
Servlet生命周期
Servlet的生命周期是由tomcat服务器控制的。
构造方法:创建servlet对象的时候调用。默认情况下,第一次访问Servlet的时候创建Servlet对象只调用1次,这也可以说明Servlet对象在tomcat是单实例的。
init方法:创建完servlet对象的时候调用,只调用1次。
service方法:每次发出请求时调用,会被调用n次。
destroy方法:销毁Servlet对象的时候调用,停止服务器或者重新部署web应用时销毁servlet对象,只调用1次。
public class FirstServlet extends HttpServlet {
public FirstServlet(){
System.out.println("FirstServlet对象构造完成");
}
@Override
public void init(ServletConfig servletConfig){
System.out.println("init()方法被调用");
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("service()方法被调用");
doGet(request,response);
}
@Override
public void destroy(){
System.out.println("destroy()方法被调用");
}
/**
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("this is first servlet");
}
/**
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
Servlet自动加载
默认情况下,第一次访问Servlet的时候创建Servlet对象。如果Servlet的构造方法或init方法中执行了比较多的逻辑代码,这样会导致用户第一次访问sevrlet的时候比较慢。
在Servlet的配置信息中,加上一个<load-on-startup>配置信息,这样就可改变servlet创建对象的时机,提前到加载web应用的时候。
<servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>ysdrzp.servlet.FirstServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/first</url-pattern> </servlet-mapping>
有参init方法和无参init方法
/** * 有参数的init和无参的init方法 */ public class InitServlet extends HttpServlet { /** * 有参数的init方法 * 该方法是Servlet的生命周期方法,一定会被tomcat服务器调用 * 注意:如果要编写初始代码,不需要覆盖有参数的init方法 */ /*@Override public void init(ServletConfig config) throws ServletException { System.out.println("有参数的init方法被调用"); }*/ /** * 无参数的init方法 * 该方法是Servlet的编写初始化代码的方法,是设计出来专门给开发者进行覆盖,然后在里面编写Servlet的初始逻辑代码的方法。 */ @Override public void init() throws ServletException { System.out.println("无参数的init方法被调用"); } }
Servlet线程安全
Servlet对象在tomcat服务器是单实例多线程的。正因为Servlet是多线程的,所以当多个Servlet的线程同时访问了Servlet的共享数据,如成员变量,可能会引发线程安全问题。
解决办法:
1)把使用到共享数据的代码块进行同步(使用synchronized关键字)
2)建议在Servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步,而且尽量缩小同步代码块的范围,避免因为同步而导致并发效率降低。
public class ThreadServlet extends HttpServlet { int count = 1; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); synchronized (ThreadServlet.class) { response.getWriter().write("你是第"+count+"位仿客。"); /*try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }*/ count++; } } }