Tag Archive for Tomcat

Servlet相关

这个东西是现在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在初始化后就保留在内存中,因此每次作出请求时无需加载。
JSP 的执行过程
(1) 客户端发出Request (请求);
(2) JSP Container 将JSP转译成Servlet的源代码;
(3) 将产生的Servlet 的源代码经过编译后,并加载到内存执行;
(4) 把结果Response (响应)至客户端。
在执行 JSP 网页时,通常可分为两个时期:转译时期(Translation Time)和请求时期(Request Time)
转译时期:JSP网页转译成Servlet类。
请求时期:Servlet类执行后,响应结果至客户端。
注:
转译期间主要做了两件事情:将JSP网页转译为 Servlet 源代码(.java),此段称为转译时期(Translation time);将Servlet源代码(.java)编译成 Servlet 类(.class),此段称为编译时期(Compilation time)。

Servlet 的生命周期
1) 产生 Servlet,加载到Servlet Engine中,然后调用 init()这个方法来进行初始化工作。
2) 以多线程的方式处理来自Client 的请求。 service()
3) 调用 destroy()来销毁Servlet,进行垃圾收集 (garbage collection)。
Servlet 从产生到结束的流程
1. 加载和实例化
当Container一开始启动, 或是客户端发出请求服务时, Container会负责加载和实例化一个Servlet。
2. 初始化
Servlet 加载并实例化后,再来Container必须初始化 Servlet。初始化的过程主要是读取配置 信息(例如JDBC连接)或其他须执行的任务。我们可以借助 ServletConfig 对象取得 Container的 配置信息,例如:
<servlet>
<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>
其中user为初始化的参数名称;browser 为初始化的值。因此,可以在 HelloServlet程序中使用ServletConfig 对象的getInitParameter(“user”)方法来取得 browser。
3. 处理请求
Servlet被初始化后,就可以开始处理请求。每一个请求由 ServletRequest 对象来接收请求;而ServletResponse对象来响应该请求。
4. 服务结束
当 Container 没有限定一个加载的 Servlet 能保存多长时间,因此,一个 Servlet 实例可能只在Container中存活几毫秒,或是其他更长的任意时间。一旦 destroy( )方法被调用时,Container将移除该 Servlet,那么它必须释放所有使用中的任何资源,若 Container 需要再使用该 Servlet时,它必须重新建立新的实例。
1. 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。
例如:

Java代码
  1. RequestDispatcher rd = request.getRequestDispatcher(“\error.jsp”);
  2. rd.forward(request, response);
  • 关于Session的持久化
  • 作用:
    提高服务器内存利用率,保持会话
    集群系统中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的请求,调度者线程从线程池中选出一个工作者线程,将请求传递给该线程,然后由该线程来执行Servlet的service方法。 当这个线程正在执行的时候,容器收到另外一个请求,调度者线程将从池中选出另外一个工作者线程来服务新的请求,容器并不关系这个请求是否访问的是同一个Servlet还是另外一个Servlet。 当容器同时收到对同一Servlet的多个请求,那这个Servlet的service方法将在多线程中并发的执行。 (这里容易出问题,所以在servlet尽量减少成员变量(实例变量)的声明,如果必须使用 ,那么需要加上同步操作,保持同步。见下)
    线程池实际上是等待执行代码的一组线程叫做工作者线程(Worker Thread),Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。 )

    变量的线程安全:
    实例变量是线程不安全的
    解决:
    实例变量—-》局部变量(方法级变量 每次方法调用的时候构造~结束的时候销毁)
    同步doXXX()方法
    (本地变量:每个线程都将拥有user变量的拷贝,线程在对自己栈中的本地变量的改变不会影响其他线程本地变量的拷贝)
    Servlet容器对它所接收到的每一个请求,都创建一个新的ServletRequest对象,所以ServletRequest对象只在一个线程中被访问。
    在这些窗口的访问请求,属于同一个session,为了同时处理多个这样的请求,Servlet容器会创建多个线程,而在这些线程中,就可以同时访问到Session对象的属性。

    SSH整合全步骤

    上一篇是整合的例子 。
    这篇是对例子的总结提取出步骤。适合初学者

    安装所需软件环境:

    1、首先安装JDK,配置Java环境变量

    右键我的电脑->属性->高级->环境变量

    【JAVA_HOME】“F:\Java\jdk1.6.0_12”jdk1.6.0_12是我装的版本,你看你自己的版本然后改下名字;

    【Path】“%JAVA_HOME%\bin;”注意,这个要添加到系统原来的PATH前面,要像有些人说的加后面可能会不能编译。

    【Classpath】“.;%JAVA_HOME%\lib\tools.jar”

    然后就是试下看是否配置成功了

    关于设置JAVA HOME的必要性:你若装TOMCAT或ORACLE等都会改变你的环境设置,总是改path,classpath容易出错也不方便,所以JAVA HOME就有了统一指向性,方便不易出错

    开始-运行-CMD然后“javac”会出现很多操作说明,也可以“java -version”查看版本信息。再就是自己编个简单的JAVA文件试下了

    2、安装MyEelipse 。注:修改Content Assist为Ctrl+Enter,可以修改提示快捷键

    3、Oracle(企业版),注意:

    1)“口令管理”中,SYSTEM、SYS和SCOTT不锁定账户,并输入新口令。

    2)“安装结束”中把iSQL*Plus URL和Enteprise Manager 10g Database Control URL两个路径记下来,登陆

    3)修改服务:右击“我的电脑”——>管理——>服务——>找到Oracle的服务,均修改为手动启动。

    4)首选项——>首选身份证明——>修改主机:

    A、设置计算机管理器中的Administrator的密码;b 、控制面板——>管理工具——>本地安全设置(策略)——>用户权利指派——>作为批处理作业登陆

    (2和4不做也可以)

    4、安装tomcat,并将tomcat加载到MyElipse中的服务器中。具体步骤为:Window ——>Preferences ——> MyEclipse Enterprise Workbench —— > Servers ——>Tomcat ——>Tomat6X——>选择”Enable”,下面三个空指向tomcat的安装路径,如:D:\Tomcat 6.0。

    环境配置好了就可以做SSH整合的项目,具体如下:

    1、先引入Struts,然后是Spring,最后是Hibernate(AOP Librarian,Core Libraries,JDBC LIbrarian,WebS Librarian)。

    2、在Database Driver中先创建数据库,driverClassName为:oracle.jdbc.driver.OracleDriver

    Url为jdbc:oracle:thin:@localhost:1521:orcl;

    3、在struts—config.xml中配置

    这样就把Struts中的ActionSevlet加到Spring中了。

    4、写带有Form表单的页面

    5、写对应的ActionForm,并在struts-config.xml中注册

    6、写对应于数据库的持久化类,如emp.hbm.xml,注其头部为:

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    内容格式为:

    //注:name为与数据库表字段相对应的类

    //说明主键类型

    然后将其在applicationContext.xml中配置:

    xml/User.hbm.xml

    7、写DAO层的接口(DAOInterface),并写实现该接口的类(DAOImpl),该类还要继承HibernateDaoSupport,且bean注入时要记得属性sessionFactory的注入。

    8、写Service层的接口,并写实现该接口的类,在该类中要定义一个EmpDAO 类型的属性,并写其get和set方法。在此类的方法中调用DAO层中的方法。

    9、写Action类,继承Action,在该类中定义一个EmpService类型的属性,并写其set方法,然后在execute方法中进行操作。

    10、将DAO、Service中所有的类和Action类注入到applicationContext.xml的Bean中,而且有属性的一定要配置属性,然后在Struts-config.xml中写 :

    name="addEmpForm"

    attribute="addEmpForm"

    scope="request"

    input="/addEmp.jsp" type="org.springframework.web.struts.DelegatingActionProxy">//代理

    11、在applicationContext中配置事务:

    class="org.springframework.orm.hibernate3.HibernateTransactionManager">

    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    PROPAGATION_REQUIRED

    12、若使用验证框架,则需先在sturts-config.xml中配置插件:

    13、在/WEB-INF下建立validation.xml,其头部为:

    "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"

    "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">

    注:tomcat的lib包里要包含objdbc14.jar的jar包。

    使用Spring、Hibernate、Struts的一些错误个人总结

    1.错误: java.lang.NullPointerException
    (当然这个错的原因偶很多这里总结的都是在SSH下容易出现的错误 8-O
    原因: 发现 dao 实例、 manage 实例等需要注入的东西没有被注入

    解决:这个时候,你应该查看日志文件;默认是应用服务器的 log 文件,比如 Tomcat 就是 [Tomcat 安装目录 ]/logs ;你会发现提示你:

    可能是:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sf’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is org.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml

    org.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml

    ……………………….

    Caused by: java.io.FileNotFoundException: src”hibernate.cfg.xml

    可能是:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sessionFactory’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception is org.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found

    org.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found

    然后你就知道原因是因为配置文件的解析出了错误,这个通过 Web 页面是看不出来的。

    更多的是持久化映射文件出的错误;导致了没有被解析;当然你需要的功能就无法使用了。

    2. 错误:
    StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
    javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage

    或者:type Status report message Servlet action is not available

    descrīption The requested resource (Servlet action is not available) is not available.

    原因: 同 1

    3. 错误StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exception

    java.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei

    界面错误具体描述:

    org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei

    原因与解决:

    <方案一>你的“html:”开头的标签没有放在一个

    <方案二>重新启动你的应用服务器,自动就没有这个问题了

    4. 错误:Exception in thread “main” org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update

    原因与解决:

    因为Hibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog=”***”(*表示数据库名称)这样的属性,将该属性删除就可以了(但是很多时候还是不行啊 :(

    5. 错误:org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)

    原因与解决:
    方法1 删除Set方的cascade
    方法2 解决关联关系后,再删除
    方法3 在many-to-one方增加cascade 但值不能是none
    最后一招:
    检查一下hashCode equals是否使用了id作为唯一标示的选项了;我用uuid.hex时是没有问题的;但是用了native,就不行了,怎么办?删除啊!

    6. 错误:exception javax.servlet.ServletException: BeanUtils.populat root cause

    java.lang.IllegalArgumentException:Cannot invoke ***Form.set*** – argument type mismatch

    原因

    这个问题很奇怪的说,为啥说奇怪呢?

    先说问题的原因:问题发生如下两种情况:

    * Form中是Date类型

    * 上传文件时

    为什么说奇怪呢?主要针对Form是日期型的来说的;因为我做过N多系统Form中都是用java.util.Date,界面使用;都是没有问题的。所以第一次遇到这个错误时,捣鼓了一个下午。

    解决:

    第一个问题:你把Date换成String;在Action中进行转换;当然转换要借助于SimpleDateFormate方法喽

    第二个问题:记得在form中增加enctype=”multipart/form-data” 呵呵

    7. 问题:

    今天用Tomcat5.5.12,发现原来很好用的系统不能用了,反复测试发现页面中不能包含 taglib,否则会出现以下提示:

    HTTP Status 500 -type Exception report

    Message

    descrīption The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    org.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD “META-INF/tlds/struts-bean.tld” from JAR file “file:*****/WEB-INF/lib/struts.jar”:

    原因:

    更新了工程用的lib文件夹下的jar,发布时也发布了servlet.jar和jsp-api.jar。

    解决:

    把jsp-api.jar删除就解决这个问题了。

    8. 问题:Tomcat5.0.20中差错可以通过[Tomcat安装目录]/logs下的localhost_log.2006-07-14.txt类似的文件看具体的错误日志,但是在5.5中就找不到了

    原因与解决:

    我把[Tomcat安装目录]/bin下的tomcat5w.exe的logging标签捣鼓了一会,然后重起就有了。

    原因具体说不准,用非安装版也有这个问题。

    最终解决方案:
    :lol: 官方文档 http://tomcat.apache.org/tomcat-5.5-doc/logging.html

    无觅相关文章插件,快速提升流量