这个东西是现在J2EE下的基础component了~
作为一个开发者~其实非常容易的使用~但是只是停留在开发的层面上还是远远不够的~
之前开发过很多servlet的程序。~我甚至不知道:
他的架构里主要类是啥?他和WEB容器的调优解决方案都有哪些?SessionId是怎么生成的?
其实这些都是基础 呜呜~我之前不重视~~不过还来得及~我慢慢加强基础。。。。。 ![]()
现在有空稍微整理下~
老生常谈之servlet生命周期~
其实servlet本质是多线程~为了解决内存资源不够的问题。对比于CGI可以说明问题。
Servlet的生命周期分为5个阶段: 实例化:Servlet容器创建Servlet类的实例。 初始化:该容器调用init()方法,通常会申请资源。 服务:由容器调用service()方法,(也就是doGet()和doPost())。 破坏:在释放Servlet实例之前调用destroy()方法,通常会释放资源。 不可用:释放内存的实例。 CGI(Common Gateway Interface通用网关接口)程序来实现数据在Web上的传输,使用的是如Perl这样的语言编写的,它对于客户端作出的每个请求,必须创建CGI程序的一个新实例,这样占用大量的内存资源。由此才引入了Servlet技术。 Servlet是一个用java编写的应用程序,在服务器上运行,处理请求信息并将其发送到客户端。对于客户端的请求,只需要创建Servlet的实例一次,因此节省了大量的内存资源。Servlet在初始化后就保留在内存中,因此每次作出请求时无需加载。
(2) JSP Container 将JSP转译成Servlet的源代码;
(3) 将产生的Servlet 的源代码经过编译后,并加载到内存执行;
(4) 把结果Response (响应)至客户端。
转译时期:JSP网页转译成Servlet类。
请求时期:Servlet类执行后,响应结果至客户端。
2) 以多线程的方式处理来自Client 的请求。 service()
3) 调用 destroy()来销毁Servlet,进行垃圾收集 (garbage collection)。
1. 加载和实例化
当Container一开始启动, 或是客户端发出请求服务时, Container会负责加载和实例化一个Servlet。
2. 初始化
Servlet 加载并实例化后,再来Container必须初始化 Servlet。初始化的过程主要是读取配置 信息(例如JDBC连接)或其他须执行的任务。我们可以借助 ServletConfig 对象取得 Container的 配置信息,例如:
<servlet-name>HelloServlet</servlet-name>
<servlet-class>tw.com.javaworld.CH2.HelloServlet</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>browser</param-value>
</init-param>
</servlet>
3. 处理请求
Servlet被初始化后,就可以开始处理请求。每一个请求由 ServletRequest 对象来接收请求;而ServletResponse对象来响应该请求。
4. 服务结束
当 Container 没有限定一个加载的 Servlet 能保存多长时间,因此,一个 Servlet 实例可能只在Container中存活几毫秒,或是其他更长的任意时间。一旦 destroy( )方法被调用时,Container将移除该 Servlet,那么它必须释放所有使用中的任何资源,若 Container 需要再使用该 Servlet时,它必须重新建立新的实例。
Servlet是一种可以在Servlet容器中运行的组件,那么理所当然就应该有一个从创建到销毁的过程,这个过程我们可以称之为 Servlet生命周期。Servlet的生命周期可以分为加载、实例化、初始化、处理客户请求和卸载五个阶段,体现在方法上主要是init()、 service()和destroy()三个方法。生命周期的具体说明如下:
Servlet容器完成加载Servlet类和实例化一个Servlet对象
init()方法完成初始化工作,该方法由Servlet容器调用完成
service()方法处理客户端请求,并返回响应结果
destroy()方法在Servlet容器卸载Servlet之前被调用,释放一些资源
2. Servlet的实例是在生命周期什么时候创建的? 配置servlet最重要的是什么?
Servlet实例是在servlet第一次在容器中被加载的是时候创建的, Init()方法是用来配置这个servlet实例的,这个方法在servlet的生命周期中只被调用一次,所以应该把所有servlet生命周期中的配置操作都写在这个方法法里面。
3. 为什么不在Servlet中写一个构造(Contructor)方法?
容器会自动为Servlet写一个无参的构造方法
4. 我们没有写servlet的构造方法,那么容器是怎么创建servlet的实例呢?
容器会自动为Servlet写一个无参的构造方法,容器是用Class.forName(className).newInstance()来创建servlet的实例的。
5. 当容器调用servlet的destory()方法的时候,servlet会马上销毁么? 如果当时这个servlet正在执行其他任务或者线程呢?
是的, 当容器调用servlet的destory()方法的时候,servlet会马上销毁,但是容器在调用destory()方法之前,会等servlet的service()方法结束剩余的任务。
6. 用ServletRequest和ServletContext调用ReqestDispatcher有什么区别?
在用ServletRequest调用RequestDispatcher的时候可以用相对URL, 但是ServletContext不行。
7. 为什么在用ServletRequest.getRequestDispatcher()的时候可以用相对URL而用ServletContext.getRequestDispatcher()的时候不可以?
因为ServletRequest包含当前的request path,可以用当前的request path去计算URL,但是ServletContext不包含当前的request path。
例如:
- RequestDispatcher rd = request.getRequestDispatcher(“\error.jsp”);
- rd.forward(request, response);
作用:
提高服务器内存利用率,保持会话
集群系统中session对象的复制
Web应用程序关闭后重启,会话继续
背景:如果内存中大量HttpSession对象堆积,会造成大量的内存消耗~毕竟session不是cookie那样,大小限制的很死。
解决方案:Web服务器将暂时不活动但未超时的HttpSession对象转移到文件系统或DB中保存,一旦需要他们是,再从File system活DB中装载进内存;
应用:Tomcat的Session持久化管理
Tomcat使用Session Manager类来管理Session的持久化
StandardManager:
默认的方法。当Tomcat服务器重启或重载的时候,会把Session对象保存到 <%CATALINA_HOME%>/work/Catalina/honstname/applicatonname/SESSIONS.ser
PersitentManager
更加灵活的管理方式,配置性强
可以存储在本地文件( (节点下添加如下节点)和数据库中(配置store节点 )
sessions.ser的生成和加载:
形式一:存储在本地文件中:配置conf目录里的context.xml文件 在节点下添加如下节点:
debug=0 saveOnRestart="true" maxActiveSession="-1" minIdleSwap="-1" maxIdleSwap="-1" maxIdleBackup="-1"
形式二:存储在数据库中 配置store节点
Tomcat在启动时加载,并不是需要时加载.
Servlet采用多线程来处理多个请求

当容器收到一个访问Servlet的请求,调度者线程从线程池中选出一个工作者线程,将请求传递给该线程,然后由该线程来执行Servlet的service方法。 当这个线程正在执行的时候,容器收到另外一个请求,调度者线程将从池中选出另外一个工作者线程来服务新的请求,容器并不关系这个请求是否访问的是同一个Servlet还是另外一个Servlet。 当容器同时收到对同一Servlet的多个请求,那这个Servlet的service方法将在多线程中并发的执行。 (这里容易出问题,所以在servlet尽量减少成员变量(实例变量)的声明,如果必须使用 ,那么需要加上同步操作,保持同步。见下)
(线程池实际上是等待执行代码的一组线程叫做工作者线程(Worker Thread),Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。 )
变量的线程安全:
实例变量是线程不安全的
解决:
实例变量—-》局部变量(方法级变量 每次方法调用的时候构造~结束的时候销毁)
同步doXXX()方法
(本地变量:每个线程都将拥有user变量的拷贝,线程在对自己栈中的本地变量的改变不会影响其他线程本地变量的拷贝)
Servlet容器对它所接收到的每一个请求,都创建一个新的ServletRequest对象,所以ServletRequest对象只在一个线程中被访问。
在这些窗口的访问请求,属于同一个session,为了同时处理多个这样的请求,Servlet容器会创建多个线程,而在这些线程中,就可以同时访问到Session对象的属性。