目录
面试题
一、Servlet的生命周期
1.类加载和实例化
Servlet容器(如Tomcat)负责加载和实例化Servlet。当容器是首次启动或首次请求某个Servlet时,容器就会读取web.xml或@WebServlet中的配置信息,对指定的Servlet进行加载。加载成功后,容器会通过反射对Servlet进行实例化,这里反射的本质就是调用Servlet的无参构造方法。容器会调用ServletContext的getServlet方法来获取Servlet实例。
2.初始化
Servlet实例化之后,Servlet容器调用Servlet的init()方法,初始化的目的是为了让Servlet在处理请求之前完成一些初始化的工作,比如建立与数据库的连接,获取配置信息等。在servlet的整个生命周期内,该方法只会被执行这一次。
3.就绪状态
当Servlet完成初始化后,容器就会将它放入就绪状态,表示它已经准备好处理客户端请求了。
3.客户端发送一个请求,Servlet容器解析并处理请求
当客户端发起请求时,Servlet容器会为每个请求创建一个新的线程,并且调用Servlet的service()方法处理请求。当Servlet容器接收到来自客户端的请求时,容器会针对该请求分别创建一个ServletRequest对象和ServletResponse对象,并将他们以参数的形式传入service()方法内,后续通过调用该方法处理请求。在service()方法中,Servlet通过ServletRequest对象获取客户端的相关信息和请求信息。请求处理完后,又通过ServletResponse对象将响应信息进行包装返回给客户端。当Servlet容器将响应信息返回给客户端后,这两个对象就会被销毁,即这两个对象的生命周期是单次请求内。在Servlet的整个生命周期内,对于Servlet的每一次请求,Servlet容器都会调用一次service()方法,并创建新的ServletRequest和ServletResponse对象。Tomcat(Servlet容器) 从 Socket 中读到的 HTTP 请求是一个字符串, 然后会按照 HTTP 协议的格式解析成一个
4.销毁阶段
当Servlet容器关闭或重启时,servlet的生命周期结束。容器就会调用destory()方法,释放该实例Servlet使用的资源,如关闭数据库连接、保存会话数据等。随后该实例会被Java的垃圾回收器回收。在Servlet的整个生命周期内,该方法只被调用一次。
二、Servlet的生命周期演示图
三、线程安全问题
Servlet是线程不安全的,通过Servlet的生命周期发现,它是个单例模式。正是因为单例模式才更应该要考虑线程安全问题。当每个用户请求时,都会为他们创建一个新的线程。即单实例多线程。优点是,缺点是存在线程安全问题。比如Servlet代码逻辑中有去全局变量。多线程下所有线程共享实例变量。出现临界值,就会引发线程安全问题。
四、解决线程安全问题
- 不使用实例(全局)变量。事实上,线程安全问题大多是由实例(全局)变量造成的。建议使用。
- 使用Synchronized加锁,保证一次只有一个线程可以访问被保护的区段,加锁实际上也是将多线程并发执行变成串行执行了。这样当大量用户访问同一资源时,用户只能排队一个一个访问,就会出现阻塞状态,造成用户的不好体验,不建议使用。
五、HttpServletRequest的一些核心方法
方法
|
描述
|
String getProtocol()
|
返回请求协议的名称和版本。
|
String getMethod()
|
返回请求的
HTTP
方法的名称,例如,
GET
、
POST
或
PUT
。
|
String getRequestURI()
|
从协议名称直到
HTTP
请求的第一行的查询字符串中,返回该请 求的 URL
的一部分。
|
String getContextPath()
|
返回指示请求上下文的请求
URI
部分。
|
String getQueryString()
|
返回包含在路径后的请求
URL
中的查询字符串。
|
Enumeration getParameterNames()
|
返回一个
String
对象的枚举,包含在该请求中包含的参数的名 称。
|
String getParameter(String name)
|
以字符串形式返回请求参数的值,或者如果参数不存在则返回null。
|
String[]
getParameterValues(String name)
|
返回一个字符串对象的数组,包含所有给定的请求参数的值,如 果参数不存在则返回NULL
|
Enumeration getHeaderNames()
|
返回一个枚举,包含在该请求中包含的所有的头名。
|
String getHeader(String name)
|
以字符串形式返回指定的请求头的值。
|
String getCharacterEncoding()
|
返回请求主体中使用的字符编码的名称。
|