1:Servlet简介
Servlet是一种运行于服务器端的java应用程序。通过创建一个java类,然后实现servlet接口就可以生成一个servlet。
ServletAPI包括:
- javax.servlet.* 主要包括所有servle实现的基本接口以及继承的基本类。
- java.servlet.http.*包含了编写基于HTTP协议的servlet所需基类。
Servlet生命周期:
初始阶段
当客服端第一次发送某个servlet请求的时候,会调用这个servlet的init()方法进行初始化,这个servlet未被卸载之前只能初始化一次。服务阶段
客服端每次发送servlet请求的时候,会调用service()方法给予响应,在service()方法中处理对应的业务逻辑。卸载阶段
当servlet容器确认某个servlet不再提供服务的时候,会卸载这个servlet程序,释放对应的servlet资源,同时这个servlet的生命周期也随之结束。
2:Servlet运行过程
客服端发送一个servlet请求服务端,服务端会检查当前servlet是否已经装载并创建对象。
如果当前servlet对象已经存在,直接执行步骤4,否则执行步骤2, 当前Servlet实例化并生成一个对象
调用当前Servlet对象的init()方法
创建一个用于封装HTTP请求的对象HttpServletResquest与响应对象HttpServletResponse。并把这个两个对象传入service方法中。
Servlet引擎卸载Servlet,在卸载之前调用destory()方法进行销毁。
3:Servlet线程安全问题
当多个客服端去访问服务端的Servlet的时候,服务端会为每个客服端都创建一个线程,这些线程都会去调用service方法,在这个service方法中可能会去访问同一个资源,因此就会发生线程安全问题。
public class ServletThreadDemo extends HttpServlet {
private static final long serialVersionUID = 1L;
private int global_x=0; //定义一个全局变量
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
int local_x = 0; //定义一个局部变量
try {
global_x++;
local_x++;
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* 通过在两个不同的浏览器分别访问这个Servlet,最终在控制台的输出为:
* global_x:2 local_x:1
* global_x:2 local_x:1
* 通过控制台的输出可以得出:全局变量为一个共享的变量,局部变量为每个线程私有的变量。当多个线程同时访问同一个servlet的时候,全局变量会发生线程安全问题,局部变量不会发生线程安全问题
* 当客户端请求servlet时,会去判断servlet容器中是否有当前servlet实例,如果没有就会根据web.xml的配置去实例化当前的servlet,否则就直接用servlet容器中存在的实例。
* 因此该servlet为单例模式。每个线程都拥有自己的栈区,栈区是线程私有的,局部变量存放在栈区中,全局变量存放在方法区中,是所有线程共享的。
*
*/
System.out.println("global_x:"+global_x+" local_x:"+local_x);
}
4:ServletConfig讲解
4.1:配置Servlet初始化参数
<servlet>
<servlet-name>ServletConfigDemo01</servlet-name>
<servlet-class>com.lx.study.servlet.ServletConfigDemo01</servlet-class>
<!-- 通过<init-param>标签为ServletConfigDemo01配置初始化参数 -->
<init-param>
<param-name>name</param-name>
<param-value>liaoxue</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
<init-param>
<param-name>charset</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
4.2:通过ServletConfig获取配置的初始化参数
public class ServletConfigDemo01 extends HttpServlet {
private static final long serialVersionUID = 1L;
//定义ServletConfig来接收当前Servlet配置的初始化参数
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
this.config=config;
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
* 当Servlet被实例化的时候,会通过init(ServletConfig config)方法把初始化参数封装到ServletConfig对象中
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String paramVal=config.getInitParameter("name");
response.getWriter().println(paramVal);
Enumeration<String> params = config.getInitParameterNames();
while(params.hasMoreElements()){
String name=params.nextElement();
String value=config.getInitParameter(name);
response.getWriter().println("name="+name+" value="+value);
}
}
页面输出:
5:ServletContext对象讲解
Web容器在启动的时候,他会为每个web应用程序去创建一个ServletContext对象。在程序代码中可以通过ServletConfig对象获取ServletContext。ServletContext是当前web中所有servlet共享的一个对象,所以可以通过ServletContext对象实现不同servlet间的通信传递。
5.1: 多个Servlet通过ServletContext对象实现数据共享
存放共享数据:
public class ServletConfigDemo01 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 通过ServletContext对象中存放当前web应用共享的数据
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext sc =this.getServletConfig().getServletContext();
String data="aaa";
sc.setAttribute("data", data);
}
在另外一个servlet中取出共享数据:
@WebServlet("/ServletConfigDemo02")
public class ServletConfigDemo02 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 获取ServletContext对象中存放当前web应用共享的数据
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext servletContext = this.getServletContext();
String data=(String) servletContext.getAttribute("data");
response.getWriter().write(data);
}
先运行ServletConfigDemo01保存共享数据,后运行ServletConfigDemo02 取出共享数据,运行ServletConfigDemo02 后浏览器显示内容:
5.2:获取web应用的初始化参数
在web.xml文件中使用 标签配置web应用的初始化参数
<context-param>
<param-name>url</param-name>
<param-value>jdbc://mysql://localhost:3306/test</param-value>
</context-param>
在代码中获取web的初始化参数
/**
* 获取web标签的初始化参数
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext servletContext = this.getServletContext();
//获取整个web站点的初始化参数
String url=servletContext.getInitParameter("url");
response.getWriter().print(url);
}
效果展示:
5.2:通过ServletContext实现请求转发
ServletConfigDemo04:
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String data="<h1><font color='red'>abcdefg</font></h1>";
response.getOutputStream().write(data.getBytes());
ServletContext servletContext = this.getServletContext(); //获取ServletContext对象
RequestDispatcher rd = servletContext.getRequestDispatcher("/ServletConfigDemo05"); //获取请求转发对象
rd.forward(request, response); //请求转发
}
ServletConfigDemo05:
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getOutputStream().write("servletDemo05".getBytes());
}
运行ServletConfigDemo04后浏览器效果如下:
5.3:通过ServletContext读取资源文件
代码展示:
/**
* Servlet implementation class ServletConfigDemo06
*/
@WebServlet("/ServletConfigDemo06")
public class ServletConfigDemo06 extends HttpServlet {
private static final long serialVersionUID = 1L;
private void readWebContentDirPropFIile(HttpServletResponse response) throws IOException {
// TODO Auto-generated method stub
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); //db.properties的部署路径
Properties pro=new Properties();
pro.load(is);
String driver=pro.getProperty("driver");
String url=pro.getProperty("url");
String username=pro.getProperty("username");
String psw=pro.getProperty("password");
response.getWriter().write(MessageFormat.format("driver={0},url={1},username={2},psw={3}",driver,url,username,psw));
}
/**
* 使用ServletContext读取资源文件
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setHeader("context-type", "text/html;charset=UTF-8"); //设置浏览器的编码格式
readWebContentDirPropFIile(response); //读取maven目录结构中src/main/resources中db.properties文件资源
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
使用类装载器读取文件:
ClassLoader loader=XXX.class.getClassLoader(); (XXX表示工程中的某个类)
InputStream in = loader.getResourceAsStream("资源部署相对路径");
对于大文件不能采用类装载器读取文件,否则会导致jvm内存溢出。大文件只能用ServletContext去读取。