什么是Servlet
Servlet在开发动态Web工程中,得到广泛的应用,掌握好Servlet非常重要,Servlet是SpringMVC的基石
Servlet(Java服务小程序) 特点
○ 它是由服务端调用和执行的(一句话: Tomcat解析和执行)
○ 它是用Java语言编写的,本质就是Java类
○ 它是按照Servlet规范开发的(除了tomcat->Servlet weblogic->servlet)
○ 功能强大,可以完成几乎所有的网站功能
Servlet生命周期
○ Servlet容器(Tomcat)启动时自动装载某些Servlet,实现这个需要在Web.xml文件中添加<load-on-startup>1</load-on-startup>
表示装载的顺序
○ 在Servlet容器启动后,浏览器首次向Servlet发送请求
○ Servlet重新装载时(比如tomcat进行redeploy【redeploy会销毁所有的Servlet实例】),浏览器再向Servlet发送请求的第一次、
处理浏览器请求阶段(Service方法)
○ 每收到一个Http请求,服务器就会产生一个新的线程去处理【线程】
○ 创建一个用于封装Http请求消息的ServletRequest对象和一个代表HTTP响应消息ServletResponse对象
○ 然后调用Servlet的service()
方法并将请求和响应对象作为参数传递进去
终止阶段
当Web应用被终止,或Servlet容器终止运行,或者Servlet类重新装载时,会调用destory()
方法
在Java的Web应用程序中,<load-on-startup>1</load-on-startup>
是一种配置参数,用于指定一个Servlet在Web应用程序启动时自动加载并初始化的顺序。
具体来说,<load-on-startup>
元素是在 web.xml 文件中用来配置 Servlet 的初始化顺序的。它的值可以是一个正整数,也可以是负整数或零。这个值表示 Servlet 初始化的优先级,数字越小,优先级越高。
如果 <load-on-startup>
的值是一个正整数,表示需要按照指定的顺序来初始化 Servlet。例如,<load-on-startup>1</load-on-startup>
表示该 Servlet 拥有最高优先级,会在其他没有指定 <load-on-startup>
或者值较大的 Servlet 之前被初始化。
如果 <load-on-startup>
的值是负整数或零,表示该 Servlet 不会自动加载,需要在第一次请求该 Servlet 时进行初始化。例如,<load-on-startup>0</load-on-startup>
表示该 Servlet 不会在启动时自动加载,而是在第一次访问时才会进行初始化。
Servlet通过Web.xml配置使用
public class HelloServlet implements Servlet {
/**
* 初始化
* 当Tomcat创建HelloServlet实例时,会调用initi方法
* 该方法只会调用一次
* @param servletConfig
* @throws ServletException
*/
public void init(ServletConfig servletConfig) throws ServletException {
}
/**
* @return 返回ServletConfig 也就是返回Servlet的配置
*/
public ServletConfig getServletConfig() {
return null;
}
/**
* 1. service方法会接收两个参数处理浏览器get/post请求
* 2. 浏览器每次请求Servlet时,就会调用service方法
* 3. 当Tomcat调用该方法时,会把HTTP请求的数据封装成实现了ServletRequest接口的request对象
* 4. 通过servletRequest对象可以得到用户提交的数据
* 5. servletResponse对象可以用于返回数据给Tomcat->浏览器
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service方法被调用了");
}
/**
* @return返回Servlet的信息
*/
public String getServletInfo() {
return null;
}
/**
* servlet销毁时被调用只会被调用一次
*/
public void destroy() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--web.xml主要用来配置web应用使用到的Servlet-->
<!--配置HelloServlet-->
<!--servlet-name: 给Servlet取名 该名字唯一-->
<!--servlet-class: Servlet的类的全路径: Tomcat在反射生成该Servlet需要使用-->
<!--url-pattern:这个就是该Servlet访问的url配置的路径-->
<!--我们应该这样访问servlet http://localhost:8080/helloServlet如果你的tomcat配置只有/的话那么是这个,如果/后面有内容加上/后面的-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>HiServlet</servlet-name>
<servlet-class>HiServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HiServlet</servlet-name>
<url-pattern>/hiServlet</url-pattern>
</servlet-mapping>
</web-app>
如果是第一次请求(Tomcat)
- 查看web.xml
- 看看请求的资源/helloServlet,在web.xml配置url-pattern
- 如果找到url-pattern,就会得到servlet-name HelloServlet
- Tomcat维护了一个大的HashMap<id,Servlet>,查询该HashMap,看看有没有这个Servlet实例
- 如果没有查询到该Servletname对应的id,即没有这个Servlet实例
- 就根据Servlet-name去得到servlet-class:类的全路径
- 使用反射技术,将Servlet实例化->init(),并放入到Tomcat维护的
HashMap<id,Servlet>
Servlet通过注解的方式使用
在项目的根目录下创建Annnotation
包,在该包下创建一个Servlet
/**
* 注解方式来配置
* @WebServlet 是一个注解 => Java基础 注解
* urlPattern对应web.xml的<url-pattern></url-pattern>
* @WebServlet(urlPatterns = {"/s1", "/s2"}) 代替了web.xml配置
* 浏览器可以这样访问SparrowServlet 可以http://localhost:8080/s1 或/s2来访问
* 底层使用了反射 +注解+IO+集合来支撑
* 注解方式开发Servlet和web.xml配置Servlet流程机制是一样的
* crtl + alt + ->快捷键
**/
@WebServlet(urlPatterns = {"/s1", "/s2"})
public class SparrowServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 doGet被调用了");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 doPost被调用了");
}
}
为什么加上个@WebServlet
注解就能访问到servlet呢?接下来我们模拟一下Tomcat的执行流程
/**
* @Author: 诉衷情の麻雀
* 模拟Tomcat是如果通过@WebServlet(urlPatterns = {"/s1","/s2"})
* 来装载一个Servlet的
**/
public class TestAnnotationServlet {
private static final HashMap<String, Object> hashMap= new HashMap<>();
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//1. 首先要得到扫描的包
String classAllPath = "com.sparrow.servlet.annotation.SparrowServlet";
//2.得到OkServlet的Class对象
Class<?> aClass = Class.forName(classAllPath);
//3.通过class对象,得到Annotation
WebServlet annotation = aClass.getAnnotation(WebServlet.class);
System.out.println(annotation);
String[] strings = annotation.urlPatterns();
for (String url : strings) {
System.out.println("url = " + url);
}
//如果匹配url,如果是第一次,tomcat就会创建一个SparrowServlet实例,放入到HashMap中
//为什么要放入到HashMap中,方便以后再次调用,因为Servlet是单例化的,在内存中只有一份
Object instance = aClass.newInstance();
System.out.println("instance" + instance); //SparrowServlet
//简单的模拟
hashMap.put("SparrowServlet", instance);
System.out.println(hashMap);
}
}
控制台输入信息如下:
当我们在浏览器输入http://localhost:8080/s1
还是http://localhost:8080/s2
都是能访问到的。
这是通过注解的方式配置Servlet
温馨提示
当Servlet
配置了"/**"表示可以匹配任意访问路径
建议不要使用/和 /,建议使用精准匹配,因为Tomcat默认的Servlet的配置是/ ,如果你配置了/
会拦截所有的请求
优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > / > /