Servlet和Tomcat相关知识


Java Servlet是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类别,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

Servlet工作模式

  • 客户端发送请求至服务器 
  • 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器 
  • 服务器将响应返回客户端 

通用Servlet

一般的,通用Servlet由javax.servlet.GenericServlet实现Servlet接口。程序设计人员可以通过使用或继承这个类来实现通用Servlet应用。

HttpServlet

javax.servlet.http.HttpServlet实现了专门用于响应HTTP请求的Servlet,提供了响应请求的doGet()和doPost()方法。

生命周期

当servlet被部署在应用服务器中(应用服务器中用于管理Java组件的部分被抽象成为容器)以后,由容器控制servlet的生命周期。除非特殊制定,否则在容器启动的时候,servlet是不会被加载的,servlet只会在第一次请求的时候被加载实例化。servlet一旦被加载,一般不会从容器中删除,直至应用服务器关闭或重新启动。但当容器做内存回收动作时,servlet有可能被删除。也正是因为这个原因,第一次访问servlet所用的时间要大大多于以后访问所用的时间。

注:servlet在服务器中的运行:1.加载 ->2.初始化 - > 3.调用 - 4.销毁  

servlet的生命周期在【2.初始化】后开始其生命周期,在【4.销毁】后结束其生命周期

与JSP的关系

Java服务器页面(JSP)是HttpServlet的扩展。由于HttpServlet大多是用来响应HTTP请求,并返回Web页面(例如HTMLXML),所以不可避免地,在编写servlet时会涉及大量的HTML内容,这给servlet的书写效率和可读性带来很大障碍,JSP便是在这个基础上产生的。其功能是使用HTML的书写格式,在适当的地方加入Java代码片断,将程序员从复杂的HTML中解放出来,更专注于servlet本身的内容。JSP在首次被访问的时候被应用服务器转换为servlet,在以后的运行中,容器直接调用这个servlet,而不再访问JSP页面。JSP的实质仍然是servlet。

Servlet 2.5的新特征

  1) 基于最新的J2SE 5.0开发的。 

  2) 支持annotations 。 

  3) web.xml中的几处配置更加方便。 

  4) 去除了少数的限制。 

      5) 优化了一些实例

Servlet里的过滤器

(1)过滤器的主要作用

1,任何系统或网站都要判断用户是否登录。

2,网络聊天系统或论坛,功能是过滤非法文字

3,统一解决编码

(2)创建一个过滤器:

1,生成一个普通的class类,实现Filter接口(javax.servlet.Filter;)。

2,重写接口里面的三个方法:init,doFilter,destroy。

3,然后在web.xml配置过滤器。

Servlet里的监听器

(1)监听器的作用:自动执行一些操作。

三种servlet监听器

对request的监听。对session的监听。对application的监听。

(2)创建一个session监听器:

1,生成一个普通的class类,如果是对session的监听,则实现HttpSessionListener。

2,然后重写里面的五个方法。

Sevlet解决线程不安全

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。

1 public class ConcurrentTest extends HttpServlet {
 2     PrintWriter output;
 3     @Override
 4     protected void service(HttpServletRequest request, HttpServletResponse response)
 5             throws ServletException, IOException {
 6         String  username;
 7         response.setContentType("text/html;charset=gb2312");
 8         username=request.getParameter("username");
 9         output=response.getWriter();
10         try {
11             //为了突出并发问题,在这设置一个延时
12             Thread.sleep(5000);
13             output.println("用户名:"+username+"<BR>"); 
14         } catch (Exception e) {
15             e.printStackTrace();
16         }
17     }
18 }

假设已在web.xml配置文件中注册了该Servlet,现有两个用户a和b同时访问该Servlet(可以启动两个IE浏览器,或者在两台机器上同时访问),即同时在浏览器中输入:

  a: http://localhost:8080/ServletTest/ConcurrentTest?Username=a
  b: http://localhost:8080/ServletTest/ConcurrentTest?Username=b

则浏览器a输出为空,浏览器b输出:用户名:a 用户名:b

由于b线程对实例变量output的修改覆盖了a线程对实例变量output的修改,从而导致了用户a的信息显示在了用户b的浏览器上。如果在a线程执行输出语句时,b线程对output的修改还没有刷新到主存,那么将不会出现图2所示的输出结果,因此这只是一种偶然现象,但这更增加了程序潜在的危险性。
 设计线程安全的Servlet
通过上面的分析,我们知道了实例变量不正确的使用是造成Servlet线程不安全的主要原因。

1、实现 SingleThreadModel 接口

如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题
2、同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,
3、避免使用实例变量
本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。



此部分参考链接:

http://www.cnblogs.com/gw811/archive/2012/09/07/2674859.html

Tomcat

Tomcat是一个免费的开源的Serlvet容器,它是Apache基金会的Jakarta项目中的一个核心项目,由Apache、Sun和其它一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和Jsp规范总能在 Tomcat中得到体现。

尽管Tomcat也可以作为独立的Java Web服务器,但在对静态资源(HTML、图像文件等)的处理速度,Web服务器管理等方面都不如Apache、IIS服务器等其他专业的HTTP服务器,因此在实际应用中,常常把Tomcat与其他的HTTP服务器集成使用。对于不支持Servlet/JSP的HTTP服务器,可以通过Tomcat服务器来运行Servlet/JSP组件。

当Tomcat与其他HTTP服务器集成时,Tomcat服务器的工作模式通常为进程外的Servlet容器,Tomcat服务器与其他HTTP服务器之间通过专门的插件来通信。


Tomcat的目录结构

$CATALINA_HOME   Tomcat安裝目录下面有

  • bin: 启动和关闭Tomcat脚本文件。
  • conf: Tomcat服务器的各种配置文件,包括:server.xml、web.xml、catalina.policy等。
  • lib: Tomcat服务器和所有web应用可以访问的jar包。
  • logs: Tomcat的日志文件。
  • webapps: Tomcat自带的两个web应用:admin和manager,用来管理Tomcat的Web服务。
  • work: JSP经过Tomcat编译后生成的Servlet。
  • temp: Tomcat运行时的临时文件。

Tomcat常用配置文件

server.xml:Tomcat中最重要的配置文件,定义了tomcat的体系结构,包括连接器端口、连接数、集群、虚拟目录、访问日志等的设置。

context.xml:全局context的配置文件,包括JNDI等信息的配置。

tocmat-users.xml:Tocmat管理员身份的配置文件,关键是设置管理员账号的密码。

logging.properties:Tocmat日志配置文件,可以修改默认的Tocmat日志路径和名称。


Tomcat日志配置

Tomcat日志信息包括访问日志和运行日志。

访问日志用于对用户访问系统的行为进行跟踪记录,主要记录用户访问的时间、对应的IP地址、访问的资料等信息。记录访问日志主要是基于对系统安全的考虑,对系统中一些重要、敏感信息的资料访问历史进行记录,便于对资源的访问历史进行追踪,对于敏感信息未经授权访问等进行事后追查有一定帮助。但记录访问日志会对服务器性能产生一定的影响,在生产系统中需要慎用。

运行日志主要记录程序运行的一些信息,其中的异常错误信息可以为我们定位错误。从6.0版本开始,Tomcat的日志接口采用是对Apache Commons Logging日志接口进行独立封装,缺省配置下,该日志接口采用硬编码使用java.util.logging日志框架。

由于Tomcat发布版本中独立封装的Apache Commons Logging接口并没有对接口完全实现,如果要选择不同的日志框架就需要将该日志接口替换为完全实现的版本。

缺省配置下,Tomcat是不记录访问日志的,可以通过如下配置允许Tomcat记录访问日志:

修改$CATALINA_HOME/server.xml,在Host标签下,找到如下配置信息,去掉两端的注释就会启用访问日志记录功能:

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 

prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

通过对pattern项的修改,可以改变日志输出的内容。该项值可以为: common 与 combined,对应的日志输出内容如下所示:

common: %h %l %u %t %r %s %b

combined: %h %l %u %t %r %s %b %{Referer}i %{User-Agent}i

pattern 也可以根据需要自由组合, 例如 pattern="%h %l",对 于各 fields 字段的含义请参照Tomcat官方文档。

在不同的环境下,需要设置不同的日志级别,在生产环境中,为了提高效率和稳定性,一般会将日志级别设置为相对较高的级别,而开发环境中为了跟踪程序流程,可以将日志级别调整为较低的级别。不同日志框架有不同的日志级别,常用的日志框架对应级别如下:

Java.util.logging对应的日志级别由高到低分别为:

severe > warning > info > config > fine > finer > finest

org.apache.log4j对应的日志级别由高到低分别为:

fatal > error > warn > info > debug > trace

在缺省配置下,Tomcat采用Java.util.logging日志框架,对应的配置文件为$CATALINA_HOME/ logging.properties,常用的日志级别设定方法如下:

设置catalina日志的级别为:FINE

1catalina.org.apache.juli.FileHandler.level = FINE

禁用catalina日志的输出:

1catalina.org.apache.juli.FileHandler.level = OFF

设置catalina所有的日志消息均输出:

1catalina.org.apache.juli.FileHandler.level = ALL

Log4j是目前应用最广的日志框架,可以使用Log4j替换Tomcat缺省采用的java.util.logging日志框架,步骤如下:

创建log4j配置文件log4j.properties ,保存在$CATALINA_HOME/lib 下。

从Apache官网Log4J项目下载Log4J(1.2版本以后)。

从Apache官网Tomcat项目下载tomcat-juli.jar和tomcat-juli-adapters.jar。

复制log4j.jar、tomcat-juli-adapters.jar到$CATALINA_HOME/lib下。

用tomcat-juli.jar覆盖$CATALINA_HOME/bin下的同名文件。

删除Tomcat的缺省日志配置文件$CATALINA_HOME/conf/ logging.properties,以避免生成一些冗余的空日志文件。

Tomcat 组织结构

引用自《Tomcat web开发及整合应用》张宏伟 编著

Tomcat是一个基于组件的服务器,它的构成组件都是可配置的,其中最外层的组件是CatalinaServlet容器,其他的组件按照一定的格式要求配置在这个顶层容器中。
Tomcat的各个组件是在<TOMCAT_HOME>\conf\server.xml文件中配置的(Localhost的端口就是在这里设置的),Tomcat服务器默认情况下对各种组件都有默认的实现,下面通过分析server.xml文件来理解Tomcat的各个组件是如何组织的。server.xml文件的基本组成结构如下。

<Server>                    顶层类元素:一个配置文件中只能有一个<Server>元素,可包含多个Service。
   <Service>               顶层类元素:本身不是容器,可包含一个Engine,多个Connector。
       <Connector/>         连接器类元素:代表通信接口。
          <Engine>   容器类元素:为特定的Service组件处理所有客户请求,可包含多个Host。
             <Host>    容器类元素:为特定的虚拟主机处理所有客户请求,可包含多个Context。
                <Context>   容器类元素:为特定的Web应用处理所有客户请求。
                </Context>
              </Host>
             </Engine>
     </Service>
</Server>
以上的类XML的代码就是server.xml文件的基本组成结构,一个元素代表一个组件。下面分别介绍这些组件。
.1 Server组件
Server组件对应<Server>元素,它是配置文件的最顶层元素,代表一个服务器。一个配置文件中只能有一个<Server>元素。
.2 Service组件

Service组件是一些Connector组件的集合,它本身不是一个容器,所以在这里不能定义日志等组件。一个Service组件中只能有一个Engine组件,可以包含多个Connector组件。

.3 Connector组件
Connector组件表示一个接口,通过这个接口接收客户的请求,然户发送给其他的容器组件,最后再把服务器的响应结果传递给客户。
.4容器类元素
上面介绍的3个组件本身并不能处理客户请求,也不能生成响应。Tomcat中只有3个组件是可以处理客户请求并生成响应的,这3个组件分别是EngineHostContext组件。这3个组件分别代表了不同的服务范围,通过嵌套关系可以知道3个组件的范围有如下的关系:Engine>Host>Context。
    Engine组件下可以包含多个Host组件,它为特定的Service组件处理所有客户请求。
    一个Host组件代表一个虚拟主机,一个虚拟主机中可以包含多个Web应用(Context组件)。
    Context组件代表一个Web应用。
Tomcat的各个组件关系,可以用下图描述。

 

一个JavaWeb application在Tomcat中与一个Context元素对应,也就是说一个Context元素定义了一个Java Web application,它们是一一对应的关系。
在一个Java Web应用中可以包含如下内容:
    Servlet
    JSP页面
    Java类
    静态资源(HTML文档、图片等)
    描述Web应用的描述文件
客户每次提出请求时指定要访问的资源,如果客户没有指定具体资源,Tomcat使用默认的资源响应客户,显示文件夹中的资源列表或者提示错误。相应服务的过程如下:

Tomca的心脏是两个组件:Connecter和Container。一个Container可以选择多个Connecter,多个Connector和一个Container就形成了一个Service。Service可以对外提供服务,而Server服务器控制整个Tomcat的生命周期。

  • 组件的生命线“Lifecycle”

    Service 和 Server 管理它下面组件的生命周期。 
    Tomcat 中组件的生命周期是通过 Lifecycle 接口来控制的,组件只要继承这个接口并实现其中的方法就可以统一被拥有它的组件控制了,这样一层一层的直到一个最高级的组件就可以控制 Tomcat 中所有组件的生命周期,这个最高的组件就是 Server,而控制 Server 的是 Startup,也就是您启动和关闭 Tomcat。

Tomca的两大组件:Connecter和Container

Connecter组件

一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),从Engine出获得响应并返回客户。 
Tomcat中有两个经典的Connector,一个直接侦听来自Browser的HTTP请求,另外一个来自其他的WebServer请求。Cotote HTTP/1.1 Connector在端口8080处侦听来自客户Browser的HTTP请求,Coyote JK2 Connector在端口8009处侦听其他Web Server的Servlet/JSP请求。 
Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。

Tomcat 还有其它重要的组件,如安全组件 security、logger 日志组件、session、mbeans、naming 等其它组件。这些组件共同为 Connector 和 Container 提供必要的服务。

Tomcat Server处理一个HTTP请求的过程

 
              图三:Tomcat Server处理一个HTTP请求的过程

Tomcat Server处理一个HTTP请求的过程

1、用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。 
2、Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。 
3、Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。 
4、Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。 
5、path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。 
6、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。 
7、Context把执行完之后的HttpServletResponse对象返回给Host。 
8、Host把HttpServletResponse对象返回给Engine。 
9、Engine把HttpServletResponse对象返回Connector。 
10、Connector把HttpServletResponse对象返回给客户Browser。



此部分参考链接
http://www.cnblogs.com/guanyuan/p/3494374.html
http://www.cnblogs.com/zhouyuqin/p/5143121.html#wiz_toc_2

Tomcat 常见问题总结

JVM内存溢出(OOM),分为堆内存溢出和PermGen区内存溢出:

java.lang.OutOfMemoryError: PermGen space

PermGen space(Permanent Generation space),是指内存的永久保存区域,主要用于存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中, 它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对其进行清理,所以如果应用中有很多CLASS的话,就很可能出现PermGen space错误。如果加载的Class超过MaxPermSize,就会抛出该异常,可以通过调整MaxPermSize进行解决。

java.lang.OutOfMemoryError: Java heap space 

JVM堆是指java程序运行过程中JVM可以调配使用的内存空间。JVM在启动的时候会自动设置Heap size的值,其初始空间(-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。

JDK安装及JAVA_HOME设置

启动不成功,没有日志,一般是JDK安装不正确或没有设置环境变量。

大量用户访问时浏览器没有响应

并发线程数设置太小,调整$CATALINA/conf/server.xml中连接器对应的请求处理线程数。


参考链接:http://www.cnblogs.com/doit8791/archive/2012/10/27/2742768.html




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值