Tomcat系列之Java技术详解

大纲

一、概述

二、Java

三、Servlet与JSP

四、Tomcat

注,本博文是从运维的角度来说明Java相关技术,不涉及开发相关内容。主要写给与我一样做运维的博友进行参考!(现在的博客,操作多、理论少,在这一篇博客我主要和大家说一说理论知识)(说明:本博文的一些图片自于开源社区与官方网站并不是所有内容全是原创)


一、概述

1.前言

在前面几篇博客中,我们和大家说了负载均衡器服务器、Web服务器、反向代理服务器、缓存服务器,从这篇博客开始我们和大家说说应用程序服务器,对于上述内容不了解的博友可以去参考一下我们前几篇的博客。在应用程序中最出名的有两种一种是PHP,另一种是JSP。他们都是用来进行Web开发的,特别是进行电子商务网站的开发,应用的特别多。对于我们运维来说肯定是不需要开发的。但我们得进行应用程序服务器维护的工作。前面我们和大家多次聊了PHP的应用服务器维护如,LAMP环境的搭建、LNMP环境搭建等。在这篇博客中我们主要和大家聊一聊JSP服器的应用。在说JSP的相关知识之前,我们先来回忆一下PHP相关知识点。


2.PHP相关知识

(1).PHP简介

PHP是通用服务器端脚本编程语言,其主要用于web开发以实现动态web页面,它也是最早实现将脚本嵌入HTML源码文档中的服务器端脚本语言之一。同时,php还提供了一个命令行接口,因此,其也可以在大多数系统上作为一个独立的shell来使用。


Rasmus Lerdorf于1994年开始开发PHP,它是初是一组被Rasmus Lerdorf称作“Personal Home Page Tool” 的Perl脚本, 这些脚本可以用于显示作者的简历并记录用户对其网站的访问。后来,Rasmus Lerdorf使用C语言将这些Perl脚本重写为CGI程序,还为其增加了运行Web forms的能力以及与数据库交互的特性,并将其重命名为“Personal Home Page/Forms Interpreter”或“PHP/FI”。此时,PHP/FI已经可以用于开发简单的动态web程序了,这即是PHP 1.0。1995年6月,Rasmus Lerdorf把它的PHP发布于comp.infosystems.www.authoring.cgi Usenet讨论组,从此PHP开始走进人们的视野。1997年,其2.0版本发布。


1997年,两名以色列程序员Zeev Suraski和Andi Gutmans重写的PHP的分析器(parser)成为PHP发展到3.0的基础,而且从此将PHP重命名为PHP: Hypertext Preprocessor。此后,这两名程序员开始重写整个PHP核心,并于1999年发布了Zend Engine 1.0,这也意味着PHP 4.0的诞生。2004年7月,Zend Engine 2.0发布,由此也将PHP带入了PHP5时代。PHP5包含了许多重要的新特性,如增强的面向对象编程的支持、支持PDO(PHP Data Objects)扩展机制以及一系列对PHP性能的改进。


(2).PHP Zend Engine

Zend Engine是开源的、PHP脚本语言的解释器,它最早是由以色列理工学院(Technion)的学生Andi Gutmans和Zeev Suraski所开发,Zend也正是此二人名字的合称。后来两人联合创立了Zend Technologies公司。


Zend Engine 1.0于1999年随PHP 4发布,由C语言开发且经过高度优化,并能够做为PHP的后端模块使用。Zend Engine为PHP提供了内存和资源管理的功能以及其它的一些标准服务,其高性能、可靠性和可扩展性在促进PHP成为一种流行的语言方面发挥了重要作用。


Zend Engine的出现将PHP代码的处理过程分成了两个阶段:首先是分析PHP代码并将其转换为称作Zend opcode的二进制格式(类似Java的字节码),并将其存储于内存中;第二阶段是使用Zend Engine去执行这些转换后的Opcode。


(3).PHP的Opcode

Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL。PHP执行PHP脚本代码一般会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend):

  • Scanning(Lexing) —— 将PHP代码转换为语言片段(Tokens)

  • Parsing —— 将Tokens转换成简单而有意义的表达式

  • Compilation —— 将表达式编译成Opocdes

  • Execution —— 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能


(4).PHP的加速器

基于PHP的特殊扩展机制如opcode缓存扩展也可以将opcode缓存于php的共享内存中,从而可以让同一段代码的后续重复执行时跳过编译阶段以提高性能。由此也可以看出,这些加速器并非真正提高了opcode的运行速度,而仅是通过分析opcode后并将它们重新排列以达到快速执行的目的。

常见的php加速器有:

  • APC (Alternative PHP Cache) 遵循PHP License的开源框架,PHP opcode缓存加速器,目前的版本不适用于PHP 5.4。项目地址,http://pecl.php.net/package/APC。

  • eAccelerator 源于Turck MMCache,早期的版本包含了一个PHP encoder和PHP loader,目前encoder已经不在支持。项目地址, http://eaccelerator.net/。

  • XCache 快速而且稳定的PHP opcode缓存,经过严格测试且被大量用于生产环境。项目地址,http://xcache.lighttpd.net/

  • Zend Optimizer和Zend Guard Loader Zend Optimizer并非一个opcode加速器,它是由Zend Technologies为PHP5.2及以前的版本提供的一个免费、闭源的PHP扩展,其能够运行由Zend Guard生成的加密的PHP代码或模糊代码。 而Zend Guard Loader则是专为PHP5.3提供的类似于Zend Optimizer功能的扩展。项目地址,http://www.zend.com/en/products/guard/runtime-decoders

  • NuSphere PhpExpress NuSphere的一款开源PHP加速器,它支持装载通过NuSphere PHP Encoder编码的PHP程序文件,并能够实现对常规PHP文件的执行加速。项目地址,http://www.nusphere.com/products/phpexpress.htm


(5).PHP源码目录结构

PHP的源码在结构上非常清晰。其代码根目录中主要包含了一些说明文件以及设计方案,并提供了如下子目录:

  • build —— 顾名思义,这里主要放置一些跟源码编译相关的文件,比如开始构建之前的buildconf脚本及一些检查环境的脚本等。

  • ext —— 官方的扩展目录,包括了绝大多数PHP的函数的定义和实现,如array系列,pdo系列,spl系列等函数的实现。 个人开发的扩展在测试时也可以放到这个目录,以方便测试等。

  • main —— 这里存放的就是PHP最为核心的文件了,是实现PHP的基础设施,这里和Zend引擎不一样,Zend引擎主要实现语言最核心的语言运行环境。

  • Zend —— Zend引擎的实现目录,比如脚本的词法语法解析,opcode的执行以及扩展机制的实现等等。

  • pear —— PHP 扩展与应用仓库,包含PEAR的核心文件。

  • sapi —— 包含了各种服务器抽象层的代码,例如apache的mod_php,cgi,fastcgi以及fpm等等接口。

  • TSRM —— PHP的线程安全是构建在TSRM库之上的,PHP实现中常见的*G宏通常是对TSRM的封装,TSRM(Thread Safe Resource Manager)线程安全资源管理器。

  • tests —— PHP的测试脚本集合,包含PHP各项功能的测试文件。

  • win32 —— 这个目录主要包括Windows平台相关的一些实现,比如sokcet的实现在Windows下和*Nix平台就不太一样,同时也包括了Windows下编译PHP相关的脚本。

好了,说了这么多PHP的相关知识我们就说到这吧。下面我们来说一说程序之间的跨平台。


3.C/C++与Java

在说Java之间我们来得说一说,C与跨平台的相关知识。我们都知道C语言是面向对象的语言,C++是面向对象的语言。相对于PHP语言来说C语言或者C++语言,更接近底层的语言或者说更接近于硬件。执行效率要比PHP这种解释型语言高的多。那大家想啊,我们经常用PHP来编写Web应用,那我们能不能用C语言来编写网站呢。答案是否定的,因为没有一家公司要C语言来开发网站的,大家都知道我们编写C语言都先编写后进行编译,然后再运行。那大家想啊,我们网站变动很快,几乎每天都的大量的更新,每次更新都要进行编译,然后再运行。维护成本太高了,就算是有公司出的起成本,也没有公司会用,C语言还有个致命的弱点那就是不能跨平台,比如我们的网站是在32位平台上开发的,那我们只能在32位平台上运行,而不能在64位平台上运行。所以用C语言编写的网站移植会很困难。刚才我们说到了跨平台,下面我们就说一下与平台相关的问题。


大家都知道,用C语言我们一般用来开发操作系统,而不是来用编写网站的。现在主流的操作系统有两种,一种是Windows系统,另一种是Linux系统。我们大家又知道,用C语言的操作系统都是有API接口(Application Programming Interface)的,简单来说API就是系统调用。帮助我们的开发人员更好的开发应用软件,由于操作系统的不同API又分为Windows API和Linux API。我们在Windows平台开发出来的软件在Linux上无法运行,在Linux上开发的软件在Windows上又无法运行,这就导致了软件移植困难,我们开发软要开发两份,甚至更多版本很是烦锁。后大家就规定一个统一的API接口即POSIX(Protabl Operation System 可移植操作系统规范)。


但是我们知道一个应用程序的运行,需要诸多相关的库文件来支撑的。在Windows当中的库文件是*.dll(动态链接库)而Linux当中的库文件是*.so(共享对象)。这样编写的程序,也是不能跨平台的。后来为了解决这个问题就提出是ABI接口(Application Binary Interface 应用程序二进制接口)。好了,我们说了这么多,其实就想表达两个意思。一是C语言是不能用来编写网站的,二是C语言移植困难、维护成本高。下面我们就来说一说Java。


二、Java

1.Java 简介

Java是由Sun Microsystems公司于 1995年5月推出的Java面向对象程序设计语言(以下简称Java语言)和Java平台的总称。由James Gosling和同事们共同研发,并在1995年正式推出。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。从此,Java被广泛接受并推动了Web的迅速发展,常用的浏览器均支持Javaapplet。另一方面,Java技术也不断更新。(2010年Oracle公司收购了SUN)


2.Java 组成

Java由四方面组成:

  • Java编程语言

  • Java类文件格式

  • Java虚拟机

  • Java应用程序接口(Java API)

下面我们来说一下这四个方面的关系,我们通过Java编程语言+Java应用程序接口(Java API)编写出*.java的文件(如,test.java),通过Java编译器javac(Java Complier)进行编译生成*.class的类文件(如,test.class),再通过Java类文件+Java虚拟机(JVM)运行Java程序。简单过程如下,

  • Java 程序语言+Java API ---> test.java (java程序)

  • javac(Java Complier) ---> test.class (字节码文件)

  • Java类文件+Java虚拟机 ---> 运行test.class

好了,下面我们来说一说,Java虚拟机(JVM)的组成。

JVM 组成:

  • JRE(JVM+Java SE API),是用于实现Java程序运行的最小环境。

  • JDK (Java+API+JVM),是用于实现Java程序开发的最小环境。


3.Java 平台

Java平台由Java虚拟机(Java Virtual Machine,简称JVM)和Java 应用编程接口(Application Programming Interface,简称API)构成。Java应用编程接口为此提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.5,最近版本为Java7.0。

4.Java 体系

Java分为三个体系,

  • J2SE(Java2 Platform Standard Edition,java平台标准版)

  • J2EE(Java 2 Platform,Enterprise Edition,java平台企业版)

  • J2ME(Java 2 Platform Micro Edition,java平台微型版)。

其中,Java SE则只包含了Java二进制程序(如JVM和Java字节码编译器)和Java的核心代码库,而Jave EE标准则包含了一组适用于创建企业级Web应用程序的API。Jave EE建立在Java SE的基础上,并依赖于Java SE才能正常工作。当然,任何级别的应用程序均能从Java EE中获益,但Jave EE却更适合解决大型软件系统设计中的问题。JAVA EE包含多个独立的API,Servlet和JSP就是其中的两个,而JAVA EE中著名的API中还包含如下的几个,

JAVA EE APIs:

  • EJB(Enterprise JavaBeans):JAVA相关的诸多高级功能的实现,如RMI(Remote Method Invocation), 对象/关系映射,跨越多个数据源的分布式事务等;

  • JMS(Java Message Service):高性能异步消息服务,实现JAVA EE应用程序与非JAVA程序的“透明”通信;

  • JMX(Java Management Extensions):在程序运行时对其进行交互式监控和管理的机制;

  • JTA(Java Transaction API):允许应用程序在自身的一个或多个组件中平滑地处理错误的机制;

  • JavaMail:通过工业标准的POP/SMTP/IMAP协议发送和接收邮件的机制;

Java SE APIs:

  • JNDI(Java Naming and Directory Interface):用于与LDAP服务交互的API;

  • JAXP(Java API for XML Processing):用于分析及转换XML(基于XSLT实现);


5.Java 优势

与传统程序不同,Sun 公司在推出 Java 之际就将其作为一种开放的技术。全球数以万计的 Java 开发公司被要求所设计的 Java软件必须相互兼容。“Java 语言靠群体的力量而非公司的力量”是Sun公司的口号之一,并获得了广大软件开发商的认同。这与微软公司所倡导的注重精英和封闭式的模式完全不同。Sun 公司对 Java 编程语言的解释是:Java 编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言。Java 平台是基于 Java 语言的平台。这样的平台非常流行。因此微软公司推出了与之竞争的.NET平台以及模仿Java的C#语言。


6.Java 执行过程

用Java语言来编写源代码,把它编译成Java Class文件,然后在Java VM中运行class文件;当编写程序时,通过调用类(Java API)中的方法来访问系统资源,而当程序运行时,它通过调用class文件中实现了Java API的方法也满足程序的Java API调用。Java VM和Java API一起组成了一个“平台“,所有Java程序都在其上编译和运行,因此,它们有时也被称作Java运行时环境。Java VM的主要任务是装载class文件并且执行其中的字节码。Java VM包含一个类装载器(class loader),它可以从程序和API装载class文件;而Java API的类只在程序执行中需要时才会被装载。(如上图)


Java字节码由执行引擎来执行。而不同的Java VM中,其执行引擎的实现可能各不相同。最简单的执行引擎不是一次性解释字节码,而另一种称为“即时编译器(just-in-time compiler)”的执行引擎执行速度更快,但要消耗更多的内存资源。即时编译模式下,第一次被执行的字节码会被编译成本地机器代码并缓存下来以实现“复用”。第三种执行引擎是所谓的自适应优化器,此种方法中,虚拟机始的时候解释字节码,介是会监视运行中程序的活动,并且记录下使用最频繁的代码。程序运行时,虚拟机只把那些活动最频繁的代码编译成本地代码,而不频繁的代码则仍然保留为字节码由虚拟机解释执行。自适应优化器可以使得Java VM在80%-90%的时间里执行被优化过的本地代码,而只需要编译10%- 20%对性能有影响的代码。最后一种虚拟机由硬件芯片构成,它用本地方法执行Java字节码,其执行引擎内嵌于芯片中。


三、Servlet与JSP

1. Servlet是什么?

在Client/Server应用的发展过程中,Java提供了一整套Client/Server解决方案,在这个方案中,程序可以自动地下载到客户端并执行,这就是applet。但是它仅仅是问题的一半,问题的另一半就是Servlet。Servlet可以被认为是服务器端的applet。Servlet被Web服务器加载和执行,就如同applet被浏览器加载和执行一样。Servlet从客户端(通过Web服务器)接收请求,执行某种作业,然后返回结果。使用servlet的基本流程如下:

  • 客户端通过HTTP提出请求。

  • Web服务器接收该请求并将其发给Servlet。如果这个Servlet尚未被加载,Web服务器将把它加载到Java虚拟机并且执行它。

  • Servlet将接收该HTTP请求并执行某种处理。

  • Servlet将向Web服务器返回应答。

  • Web服务器将从Servlet收到的应答发送给客户端。

由于servlet是在服务器上执行,通常与applet相关的安全性的问题并不需实现。要注意的是Web浏览器并不直接和Servlet通信,Servlet是由Web服务器加载和执行的。而Servlet是用Java编写的,所以它们一开始就是平台无关的。这样,Java编写一次就可以在任何平台运行(write once,run anywhere)的承诺就同样可以在服务器上实现了。Servlet还有一些CGI脚本所不具备的独特优点:

  • Servlet是持久的。Servlet只需Web服务器加载一次,而且可以在不同请求之间保持服务(例如一次数据库连接)。与之相反,CGI脚本是短暂的、瞬态的。每一次对CGI脚本的请求,都会使Web服务器加载并执行该脚本。一旦这个CGI脚本运行结束,它就会被从内存中清除,然后将结果返回到客户端。CGI脚本的每一次使用,都会造成程序初始化过程(例如连接数据库)的重复执行。

  • Servlet是与平台无关的。如前所述,servlet是用Java编写的,它自然也继承了Java的平台无关性。

  • Servlet是可扩展的。由于servlet是用Java编写的,它就具备了Java所能带来的所有优点。Java是健壮的、面向对象的编程语言,它很容易扩展以适应你的需求。servlet自然也具备了这些特征。

  • Servlet是安全的。从外界调用一个servlet的惟一方法就是通过Web服务器。这提供了高水平的安全性保障,尤其是在你的Web服务器有防火墙保护的时候。

Setvlet可以在多种多样的客户机上使用。由于Servlet是用Java编写的,所以你可以很方便地在HTML中使用它们,就像你使用applet一样。那么,Servlet是怎样执行的?怎样来写一个Servlet,它的基本架构是怎么样的?这些问题,将在后面部分给予介绍。


2.JSP与Servlet

现在已经对Servlet有了大概的了解,现在我们就来说说JSP和Servlet的关系。

JSP是一种脚本语言,包装了Java Servlet系统的界面,简化了Java和Servlet的使用难度,同时通过扩展JSP标签(TAG)提供了网页动态执行的能力。尽管如此,JSP仍没有超出Java和Servlet的范围,不仅JSP页面上可以直接写Java代码,而且JSP是先被译成Servlet之后才实际运行的。JSP在服务器上执行,并将执行结果输出到客户端浏览器,我们可以说基本上与浏览器无关。它是与JavaScript不同的,JavaScript是在客户端的脚本语言,在客户端执行,与服务器无关。那么JSP是什么?就是Servlet。


JSP与Servlet之间的主要差异在于,JSP提供了一套简单的标签,和HTML融合的比较好,可以使不了解Servlet的人可以做出动态网页来。对于Java语言不熟悉的人(比如像我),会觉得JSP开发比较方便。JSP修改后可以立即看到结果,不需要手工编译,JSP引擎会来做这些工作;而Servelt还需要编译,重新启动Servlet引擎等一系列动作。但是在JSP中,HTML与程序代码混杂在一起,而Servlet却不是这样。也许大家比较混乱了,那么Servlet又是什么?下面我们对JSP的运行来做一个简单的介绍,告诉大家怎样来执行一个JSP文件:

当Web服务器(或Servlet引擎,应用服务器)支持JSP引擎时,JSP引擎会照着JSP的语法,将JSP文件转换成Servlet代码源文件,接着Servlet会被编译成Java可执行字节码(bytecode),并以一般的Servlet方式载入执行。简单来说就是,*.jsp文件 -jasper引擎-> *.java文件 -javac编译器-> .class (JVM运行)。


JSP语法简单,可以方便的嵌入HTML之中,很容易加入动态的部分,方便的输出HTML。在Servlet中输出HTML则需要调用特定的方法,对于引号之类的字符也要做特殊的处理,加在复杂的HTML页面中作为动态部分,比起JSP来说是比较困难的。除去了转换和编译阶段,JSP和Servlet之间的区别实在是不大。


JSP引擎通常架构在Servlet引擎之上,本身就是一个Servlet,把JSP文件转译成Servlet源代码,再调用Java编译器,编译成Servlet。这也是JSP在第一次调用时速度比较慢的原因,在第一次编译之后,JSP与Servlet速度相同。下面我们来看看为什么他们在第一次编译后再编译的速度相同。


在整个运行过程中,JSP引擎会检查编译好的JSP(以Servlet形式存在)是否比原始的JSP文件还新。如果是,JSP引擎不会编译;如果不是,表示JSP文件比较新,就会重新执行转译与编译的过程。为了有个深刻的了解,我们看一下JSP的运行和开发环境:

  • 浏览器:常见的浏览器有IE和火狐等。

  • 据库:常用的数据库有Oracle,SQL Server,Informix,DB2,Sybase,Access,MySQL等。

  • 操作系统:常见的有Windows,Linux,以及各种Unix系统。

  • Web服务器:常见的有IIS,Apache,Netscape Enterprise Server等。

  • JSP引擎:一般JSP引擎都以Servlet引擎为基础,并以Servlet的形式出现。同时,在各种免费和商业引擎的实现中,Servlet引擎和JSP引擎通常也是一起出现,我们成为Servlet/JSP引擎,或从某种成为JSP引擎。JSP引擎是可以提供JSP和Servlet运行支持并对其生存周期进行管理的系统级实体。


在JSP页面第一次被请求时,JSP引擎会将JSP原始文件转换成Servlet源代码,然后调用Java编译器,编译成Servlet并在Servlet引擎中执行。当再次有请求的时候,JSP引擎会见差异编译好的JSP是否比原来的JSP原始文件要新。如果是,则运行Servlet;如果不是,表示文件已经更新的了,就会从新执行转换和编译的过程。


说到这里,也基本把JSP和Servlet的关系说清楚了,从我的感觉上看用JSP就可以了,简单又方便,又可以和Bean很好的兼容使用,功能又很强大,为什么又出现了Servlet,它又有什么用?何况它的编写又相对复杂。为了把问题说得更清楚一点,我想在这里说一下历史,顺便再讲一下为什么还要用Servlet,Servlet的好处是什么?


简单的说,SUN首先发展出Servlet,其功能比较强劲,体系设计也很先进。只是,它输出HTML语句还是采用了老的CGI方式,是一句一句输出。所以,编写和修改HTML非常不方便。后来SUN推出了类似于ASP的嵌入式的JSP(是Servlet发展的产物),把JSP TAG嵌入到HTML语句中,这样,就大大简化和方便了网页的设计和修改。新型的网络语言如ASP,PHP,JSP都是嵌入型的SCRIPT语言。


从Web三层结构的角度看,一个Web项目最少分三层:data layer(数据层),business layer(业务层), presentation layer(展示层)。当然也可以更复杂。S用来写business layer是很强大的,但是对于写presentation layer就很不方便。JSP则主要是为了方便写presentation layer而设计的。当然也可以写business layer。写惯了ASP,PHP,CGI的朋友,经常会不自觉的把presentation layer和business layer混在一起。把数据库处理信息放到JSP中,其实,它应该放在business layer中。


根据SUN自己的推荐,JSP中应该仅仅存放与presentation layer有关的内容,也就是说,只放输出HTML网页的部份。而所有的数据计算,数据分析,数据库联结处理,统统是属于business layer,应该放在JAVA BEANS中。通过JSP调用JAVA BEANS,实现两层的整合。


实际上,微软推出的DNA技术,简单说,就是ASP+COM/DCOM技术。与JSP+BEANS完全类似,所有的presentation layer由ASP完成,所有的business layer由COM/DCOM完成。通过调用,实现整合。现在微软推出的.NET也是通过这个理念,所有的presentation layer由ASP.NET完成,business layer由C#或VB.NET或VC.NET来完成。


为什么要采用这些组件技术呢?因为单纯的ASP/JSP语言是非常低效率执行的,如果出现大量用户点击,纯SCRIPT语言很快就到达了他的功能上限,而组件技术就能大幅度提高功能上限,加快执行速度。另外一方面,纯SCRIPT语言将presentation layer和business layer混在一起,造成修改不方便,并且代码不能重复利用。如果想修改一个地方,经常会牵涉到十几页code,采用组件技术就只改组件就可以了。


综上所述,Servlet是一个早期的不完善的产品,写business layer很好,写presentation layer就很不好,并且两层混杂,显得十分混乱。所以,推出JSP+BAEN,用JSP写presentation layer,用BAEN写business layer。SUN自己的意思也是将来用JSP替代Servlet。


看了上面的叙述,大家可能对JSP与Servlet共存有了比较好的认识。可以看到JSP和Bean结合后的的实用性,强大的表现功能,易用性都是Servlet所不能及的。那么是不是Servlet就被取代了?不是!在以后的发展中,它还是有着巨大的作用的。上面只不过是将了问题的一方面,下面我们来看看Servlet本身的特点。由于它是由java来写的,所以相关的特点我们就不说了,上文已经有了详细的介绍,我们来看看其他的特点,Servlet是用于开发服务器端应用程序的一种编程模型,如果只是一个普通的java应用,可以不使用Servlet来编写,但是如果想要提供基于web的服务能力,那么就必须按照这种模型来编写,而且Servlet也必须允许在符合Servlet规范的java web server or app server之上,否则无法运行。除非你自己实现一个Web server,但是其复杂度是比较高的,特别是在企业级应用中,对系统的稳定性和健壮性都要求比较高,所以Servlet的模型实际上是简化了编写稳健的服务器端的应用开发过程。Servlet 可以作为提供web服务能力的一个接入方式,现在也许可以理解了什么是Servlet什么是JSP,它们之间的关系是怎样的。好了,知识铺垫我们就说到这了。我已经尽最大的努力来说明Servlet与JSP了,毕竟我不是开发啊。想深入了解JSP与Servlet的朋友可以可以看看Java Web开发的相关书箱。下面我们来说一说JSP运行过程。


3.JSP 运程过程

一个JSP页面有多个客户访问,下面是第一个客户访问JSP页面时候,JSP页面的执行流程:

  • 客户通过浏览器向服务器端的JSP页面发送请求

  • JSP引擎检查JSP文件对应的Servlet源代码是否存在,若不存在转向第4步,否则执行下一步

  • JSP引擎检查JSP页面是否需要修改,若没修改,转向第5步,否则执行下一步

  • JSP引擎将JSP页面文件转译为Servlet源代码(相应的 .java 代码)

  • JSP引擎将Servlet源代码编译为相应字节码( .class代码 )

  • JSP引擎加载字节码到内存

  • 字节码处理客户请求,并将结果返回给客户

在不修改JSP页面的情况下,除了第一个客户访问JSP页面需要经过以上几个步骤外,以后访问该JSP页面的客户请求,直接发送给JSP对应的字节码程序处理,并将处理结果返回给客户,这种情况下,JSP页面既不需要启动服务器,以便重新加载修改后的JSP页面。


四、Tomcat

1.概述

通过上面的讲解大家对JSP与Servlet已经有所理解,最起码知道它们是做什么的,说到底它们都是程序设计语言,是帮助我们更好的编写程序。大家都知道,不管是Servlet也好,还是JSP也好它们编写出来的应用程序都是要运行的。在Web服务器的支持下可以执行解析并且运行,最终能被用户所看到并操作,这是才我们的最终目的。那能实现对JSP与Servlet解析并运行的Web服务器有哪些呢?(注,我们一般说能解析并运行JSP与Servlet的程序为Web服务器,可在JSP与Servlet这里我们称为Web容器。在下面的内容中我们就说Web容器,也就是Web服务器)


2.常见的web容器

商业版:

  • Sun GlassFish Enterprise Server

  • Sun Java System Web Server

  • JBoss Enterprise Application Platform

  • WebLogic Application Server

  • Caucho's Resin Server

  • WebSphere Application Server

  • NetWeaver

非商业版:

  • Apache Tomcat

  • Apache Geronimo

  • GlassFish

  • JBoss Application Server

  • Jetty

  • Tiny Java Web Server

  • Eclipse Virgo

注,用的最多的不是Tomcat,我们这里主要讲解tomcat。


3.Tomcat 简介

Sun推出的JSP(Java Server Pages)是一种运行于服务器端的动态网页开发技术,它基于Java技术。执行JSP时需要在Web服务器上架设一个编译JSP网页的引擎。Tomcat服务器是Apache组织开发的一种JSP引擎同时支持Servlet,本身具有Web服务器的功能,可以作为独立的Web服务器来使用。但是,在作为Web服务器方面,Tomcat处理静态HTML页面时不如Apache迅速,也没有Apache健壮,所以我们一般将Tomcat与Apache配合使用,让Apache对网站的静态页面请求提供服务,而Tomcat作为专用的JSP引擎,提供JSP解析,以得到更好的性能。并且Tomcat本身就是Apache的一个子项目,所以Tomcat对Apache提供了强有力的支持。对于大多数网站来说,Tomcat是一个很不错的选择


Tomcat 在严格意义上并不是一个真正的应用服务器,它只是一个可以支持运行Serlvet/JSP的Web容器,不过Tomcat也扩展了一些应用服务器的功能,如JNDI,数据库连接池,用户事务处理等等。Tomcat 是一种具有JSP环境的Servlet容器。Servlet容器是代替用户管理和调用 Servlet的运行时外壳。那么什么是Servlet容器呢?


Servlet容器,负责处理客户请求。当客户请求来到时,Servlet容器获取请求,然后调用某个Servlet,并把Servlet的执行结果返回给客户。当客户请求某个资源时,Servlet容器使SERVLETREQUEST对象把客户的请求信息封装起来,然后调用JAVA Servlet API中定义的Servlet的一些生命周期方法,完成Servlet的执行,接着把Servlet执行的要返回给客户的结果封装到SERVLETRESPONSE对象中,最后SERVLET容器把客户的请求发送给客户,完成为客户的一次服务过程。


4.Tomcat 体系结构

Tomcat系列之Java技术详解_第1张图片

Tomcat 支持Servlet 2.5和JSP 2.1的规范,它由一组嵌套的层次和组件组成,一般可分为以下四类:

  • 顶级组件:位于配置层次的顶级,并且彼此间有着严格的对应关系(如,Server、Service);

  • 连接器:连接客户端(可以是浏览器或Web服务器)请求至Servlet容器,

  • 容器:包含一组其它组件,如Engine、Host、Content;

  • 被嵌套的组件:位于一个容器当中,但不能包含其它组件(如,Realm(用户账户数据库)、valve(基于用户的认证)、logger(记录日志));


顶级组件:

(1).服务器(server):Tomcat的一个实例,通常一个JVM只能包含一个Tomcat实例;因此,一台物理服务器上可以在启动多个JVM的情况下在每一个JVM中启动一个Tomcat实例,每个实例分属于一个独立的管理端口。这是一个顶级组件。


(2).服务(service):一个服务组件通常包含一个引擎和与此引擎相关联的一个或多个连接器。给服务命名可以方便管理员在日志文件中识别不同服务产生的日志。一个server可以包含多个service组件,但通常情下只为一个service指派一个server。


连接器类组件:

连接器(connectors):负责连接客户端(可以是浏览器或Web服务器)请求至Servlet容器内的Web应用程序,通常指的是接收客户发来请求的位置及服务器端分配的端口。默认端口通常是HTTP协议的8080,管理员也可以根据自己的需要改变此端口。一个引擎可以配置多个连接器,但这些连接器必须使用不同的端口。默认的连接器是基于HTTP/1.1的Coyote。同时,Tomcat也支持AJP、JServ和JK2连接器。


容器类组件:

(1).引擎(Engine):引擎通是指处理请求的Servlet引擎组件,即Catalina Servlet引擎,它检查每一个请求的HTTP首部信息以辨别此请求应该发往哪个host或context,并将请求处理后的结果返回的相应的客户端。严格意义上来说,容器不必非得通过引擎来实现,它也可以是只是一个容器。如果Tomcat被配置成为独立服务器,默认引擎就是已经定义好的引擎。而如果Tomcat被配置为Apache Web服务器的提供Servlet功能的后端,默认引擎将被忽略,因为Web服务器自身就能确定将用户请求发往何处。一个引擎可以包含多个host组件。

(2).主机(Host):主机组件类似于Apache中的虚拟主机,但在Tomcat中只支持基于FQDN的“虚拟主机”。一个引擎至少要包含一个主机组件。

(3).上下文(Context):Context组件是最内层次的组件,它表示Web应用程序本身。配置一个Context最主要的是指定Web应用程序的根目录,以便Servlet容器能够将用户请求发往正确的位置。Context组件也可包含自定义的错误页,以实现在用户访问发生错误时提供友好的提示信息。


被嵌套类(nested)组件:

这类组件通常包含于容器类组件中以提供具有管理功能的服务,它们不能包含其它组件,但有些却可以由不同层次的容器各自配置。 
(1).阀门(Valve):用来拦截请求并在将其转至目标之前进行某种处理操作,类似于Servlet规范中定义的过滤器。Valve可以定义在任何容器类的组件中。Valve常被用来记录客户端请求、客户端IP地址和服务器等信息,这种处理技术通常被称作请求转储(request dumping)。请求转储valve记录请求客户端请求数据包中的HTTP首部信息和cookie信息文件中,响应转储valve则记录响应数据包首部信息和cookie信息至文件中。 
(2).日志记录器(Logger):用于记录组件内部的状态信息,可被用于除Context之外的任何容器中。日志记录的功能可被继承,因此,一个引擎级别的Logger将会记录引擎内部所有组件相关的信息,除非某内部组件定义了自己的Logger组件。 
(3).领域(Realm):用于用户的认证和授权;在配置一个应用程序时,管理员可以为每个资源或资源组定义角色及权限,而这些访问控制功能的生效需要通过Realm来实现。Realm的认证可以基于文本文件、数据库表、LDAP服务等来实现。Realm的效用会遍及整个引擎或顶级容器,因此,一个容器内的所有应用程序将共享用户资源。同时,Realm可以被其所在组件的子组件继承,也可以被子组件中定义的Realm所覆盖。


引擎(Engine):引擎是指处理请求的Servlet引擎组件,即Catalina Servlet引擎,它从HTTPconnector接收请求并响应请求。它检查每一个请求的HTTP首部信息以辨别此请求应该发往哪个host或context,并将请求处理后的结果返回的相应的客户端。严格意义上来说,容器不必非得通过引擎来实现,它也可以是只是一个容器。如果Tomcat被配置成为独立服务器,默认引擎就是已经定义好的引擎。而如果Tomcat被配置为Apache Web服务器的提供Servlet功能的后端,默认引擎将被忽略,因为Web服务器自身就能确定将用户请求发往何处。一个引擎可以包含多个host组件。


Tomcat连接器架构:基于Apache做为Tomcat前端的架构来讲,Apache通过mod_jk、mod_jk2或mod_proxy模块与后端的Tomcat进行数据交换。而对Tomcat来说,每个Web容器实例都有一个Java语言开发的连接器模块组件,在Tomcat中,这个连接器是org.apache.catalina.Connector类。这个类的构造器可以构造两种类别的连接器:HTTP/1.1负责响应基于HTTP/HTTPS协议的请求,AJP/1.3负责响应基于AJP的请求。但可以简单地通过在server.xml配置文件中实现连接器的创建,但创建时所使用的类根据系统是支持APR(Apache Portable Runtime)而有所不同。APR是附加在提供了通用和标准API的操作系统之上一个通讯层的本地库的集合,它能够为使用了APR的应用程序在与Apache通信时提供较好伸缩能力时带去平衡效用。同时,需要说明的是,mod_jk2模块目前已经不再被支持了,mod_jk模块目前还apache被支持,但其项目活跃度已经大大降低。因此,目前更常用 的方式是使用mod_proxy模块。

如果支持APR:

  • HTTP/1.1:org.apache.cotote.http11.Http11AprProtocol

  • AJP/1.3:org.apache.coyote.ajp.AjpAprProtocol

如果不支持APR:

  • HTTP/1.1: org.apache.coyote.http11.Http11Protocol

  • AJP/1.3: org.apache.jk.server.JkCoyoteHandler


连接器协议:

Tomcat的Web服务器连接器支持两种协议:AJP和HTTP,它们均定义了以二进制格式在Web服务器和Tomcat之间进行数据传输,并提供相应的控制命令。

AJP(Apache JServ Protocol)协议:目前正在使用的AJP协议的版本是通过JK和JK2连接器提供支持的AJP13,它基于二进制的格式在Web服务器和Tomcat之间传输数据,而此前的版本AJP10和AJP11则使用文本格式传输数据。

HTTP协议:诚如其名称所表示,其是使用HTTP或HTTPS协议在Web服务器和Tomcat之间建立通信,此时,Tomcat就是一个完全功能的HTTP服务器,它需要监听在某端口上以接收来自于商前服务器的请求。


5.Tomcat 工作模式

(1).独立的Servlet容器

Tomcat 的默认工作模式,作为独立的Servlet容器,是内置在Web服务器中的一部分,是指使用基于JAVA的Web服务器的情形。其他两种方式是TOMCAT与其他服务器集成的方式。

(2).进程内的Servlet容器

Servlet容器作为Web服务器的插件和JAVA容器的实现。Web服务器的插件在内部地址空间打开一个JVM(JAVA VIRTUAL MACHINE)使JAVA容器得以在内部运行。如有某个需要调用Servlet的请求,插件将取得对此请求的控制并将它传递(使用JNI)给JAVA容器。进程内的容器对于多线程、单进程的服务器非常适合,并且提供了很好的运行速度,只是伸缩性有所不足。

注,JNI是JAVA NATIVE INTERFACE的缩写,是JAVA本地调用接口,通过JNI,JAVA程序可以和其他语言编写的本地程序进行通信。

(3).进程外的Servlet容器

Servlet容器运行于Web服务器之外的地址空间,并且作为Web服务器的插件和JVM使用IPC(如TCP/IP)进行通信。进程外容器的反应时间不如进程内的容器,但有较好的伸缩性、稳定性等性能。

IPC INTERPROCESS COMMUNICATION(进程间通信)的简写,它是实现进程间通信的一种技术。


6.Tomcat 的组织结构

Tomcat是一个基于组件的服务器,它的构成组件都是可配置的,其中最外层的给件是CATALINA SERVLET容器,其他的组件按照一定的格式要求配置在这个顶层容器中。Tomcat的各个组件是server.xml文件中配置的,Tomcat服务器默认情况下对各种组件都有默认的实现,下面通过分析server.xml文件来理解Tomcat的各个组件是如何组织的。

1
2
3
4
5
6
7
8
9
10
11
      顶层元素,代表一个服务器
     顶层元素,是Connector的集合,只有一个Engine
               连接器类元素,代表通信接口
              容器类元素,为特定的Service组件处理所有客户请求,可包含多个Host
                   为特定的虚拟主机处理所有客户请求
                        为特定的WEB应用处理所有客户请求
                   < /Context >
               < /Host >
           < /Engine >
< /Service >
< /Server >

Tomcat中真正处理客户请求与生成响应的三个组件是Engine 、Host、 Context。为了帮助大家更好的理解Tomcat的组织结构,请看下图:

好了,说到这里有关Tomcat的相关理论知识我们就讲的差不多了,在下面的一篇博客中我们将讲解Tomcat的安装与配置。希望大家有所收^_^……


本文出自 “Share your knowledge …” 博客,请务必保留此出处http://freeloda.blog.51cto.com/2033581/1298687

你可能感兴趣的:(服务器)