二、动态web 资源开发技术——Servlet
Servlet(小服务程序)是一个与协议无关的、跨平台的Web组件,由Servlet容器所管理。运行在服务器端,可以动态地扩展服务器的功能,并采用“请求一响应”模式提供Web服务。 Servlet的主要功能是交互式地浏览和修改数据,生成动态Web内容。 Servlet是按照Servlet规范编写的Java类。
Servlet生命周期
Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:
① 加载和实例化:默认情况下,当servlet第一次被访问时,由容器创建servlet对象。
② 初始化:在Servlet实例化之后,容器将调用servlet的init()方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作。该方法只调用一次。
③ 请求处理:每次请求servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理。
④ 服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的destroy()方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收。
Servlet常用方法
初始化方法,在Servlet被创建时执行,只执行一次。void init(ServletConfig config)
提供服务方法,每次Servlet被访问,都会调用该方法。void service(ServletRequest req, ServletResponse res)
销毁方法,当Servlet被销毁时,调用该方法。在内存释放或服务器关闭时销毁Servlet。void destroy()
获取ServletConfig对象ServletConfig getServletConfig()
获取Servlet信息String getServletInfo()
三、动态的网页技术——JSP
**概念:**Java Server Pages,Java服务端页面。
一种动态的网页技术,其中既可以定义HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容。
JSP = HTML + Java,JSP本质上就是一个Servlet 。
**JSP的作用:**简化开发,避免了在Servlet中直接输出HTML标签。
原理:JSP本质上就是一个Servlet 。JSP在被访问时,由JSP容器(Tomcat)将其转换为Java文件(Servlet),在由JSP容器(Tomcat)将其编译,最终对外提供服务的其实就是这个 字节码文件 。
**缺点:**JSON 只支持 get,因为 script 标签只能使用 get 请求; JSONP 需要后端配合返回指定格式的数据。
实例
//test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
Date date=new Date();
out.write(date.toLocaleString());
%>
</body>
</html>
四、Web服务器——Tomcat
结构:
Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户.而Servlet是一种运行在支持Java语言的服务器上的组件. Servlet最常见的用途是扩展Java Web服务器功能。
①Tomcat 通过 Socket 读取到这个请求(一个字符串), 并按照 HTTP 请求的格式来解析这个请求, 根据请求中的 Context Path 确定一个 webapp, 再通过 Servlet Path 确定一个具体的 类. 再根据当前请求的方法 (GET/POST/…), 决定调用这个类的 doGet 或者 doPost 等方法。
②表示Servlet容器把响应对象ServletResponse中的处理结果转发给Web服务器,通知Web服务器以HTTP响应的方式把结果发送到客户端,同时把控制返回Web服务器。
class Tomcat{
// 用来存储所有的 Servlet 对象
private List<Servlet> instanceList = new ArrayList<>();
public void start() {
// 根据约定,读取 WEB-INF/web.xml 配置文件;
// 并解析被 @WebServlet 注解修饰的类
// 假定这个数组里就包含了我们解析到的所有被 @WebServlet 注解修饰的类.
Class<Servlet>[] allServletClasses = ...;
// 这里要做的的是实例化出所有的 Servlet 对象出来;
for (Class<Servlet> cls : allServletClasses) {
// 这里是利用 java 中的反射特性做的
// 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
// 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
// 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。
Servlet ins = cls.newInstance();
instanceList.add(ins);
}
// 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;
for (Servlet ins : instanceList) {
ins.init();
}
// 利用我们之前学过的知识,启动一个 HTTP 服务器
// 并用线程池的方式分别处理每一个 Request
ServerSocket serverSocket = new ServerSocket(8080);
// 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
ExecuteService pool = Executors.newFixedThreadPool(100);
while (true) {
Socket socket = ServerSocket.accept();
// 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的
pool.execute(new Runnable() {
doHttpRequest(socket);
});
}
// 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;
for (Servlet ins : instanceList) {
ins.destroy();
}
}
public static void main(String[] args) {
new Tomcat().start();
}
}
流程:
在Tomcat容器中,当接收到HTTP请求时,会创建相应的Servlet类实例来处理该请求。Tomcat使用了Java的反射机制来创建Servlet实例,并依赖于Servlet规范的生命周期方法来管理Servlet的生命周期。
## 初始化阶段:
Tomcat在启动时会扫描应用程序的部署描述符(如web.xml文件)来获取Servlet的配置信息。
根据配置信息,Tomcat会使用Java的反射机制动态加载Servlet类,并调用其无参构造方法创建Servlet实例。
创建Servlet实例后,Tomcat会调用Servlet的init()方法将Servlet初始化,并传递一个ServletConfig对象,其中包含了Servlet的配置参数。
## 请求处理阶段:
当接收到HTTP请求时,Tomcat会根据请求的URL匹配到对应的Servlet。
Tomcat会为每个请求创建一个独立的线程,该线程负责处理该请求。
Tomcat会调用Servlet的service()方法来处理请求,将请求和响应对象作为参数传递给service()方法。
## 生命周期管理:
在Servlet的整个生命周期中,Tomcat会根据Servlet规范的要求调用相应的生命周期方法。
在Servlet实例创建后,Tomcat会调用init()方法进行初始化。
当Tomcat关闭或重新加载Web应用程序时,会调用Servlet的destroy()方法进行销毁。
在运行期间,Tomcat会根据需要调用service()方法来处理请求。
使用Java的反射机制,Tomcat可以动态地加载和实例化Servlet类,而不需要直接在代码中进行显式的实例化。通过调用Servlet的生命周期方法,Tomcat能够管理Servlet的状态和资源,并在需要时创建、初始化和销毁Servlet实例。这种基于反射和生命周期方法的机制使Tomcat能够有效地处理Servlet请求,并提供高性能和可扩展性的Web应用程序容器。
优化性能:
- 调整Tomcat线程池大小:Tomcat默认的线程池大小为200,如果在高并发的情况下,可能会导致线程池资源不足,可以通过修改Tomcat的配置文件,调整线程池大小。
- 调整JVM内存分配:Tomcat在启动时会使用JVM内存来加载应用程序和处理请求。如果JVM内存分配不合理,可能会导致内存不足或内存泄漏,可以通过调整JVM内存分配参数,如-Xms和-Xmx。
- 使用缓存:Tomcat支持多种缓存技术,如内存缓存、磁盘缓存和分布式缓存等。通过使用缓存,可以减少应用程序对数据库和其他资源的访问,提高响应速度和并发访问量。
- 使用 CDN 加速静态资源:可以使用 CDN(内容分发网络)来加速静态资源的传输,减少服务器的负载,提高网站的访问速度。
- 启用静态资源缓存:可以通过在 web.xml 中配置 filter,启用静态资源缓存,减少服务器的负载,提高访问速度。