彼岸船夫

我是一只菜鸟,在繁华城市独自飞翔,为生活有时候很迷茫,苦苦坚持在无烟沙场,期待渡船远方

tomcat(一)--java基础

什么是java

        java所涉及到的相关概念如下图。总体来说就是java语言、java API、jvm等构成。

        jvm:java虚拟机,java的代码都是运行在jvm上,这是java语言跨平台的保证,针对不同的系统jvm也不同,这就实现了同一份代码,通过不同jvm的运行可以让对应的操作系统识别。

        JRE(java running environment):就是提供给java代码一个运行环境,java代码运行在jvm上,但是开发程序的时候往往除本身代码外会有引入的api,当程序运行时,jvm会加载相关的类,所以一个能保证代码能正常运行的环境是jvm+api(java se api)。

        JDK(java development kit):java开发环境,JDK=java语言+开发相关的API+JRE。开发环境除了要正常运行程序外(JRE环境),还需要进行开发相关的操作如打包、编译等这类工具。

        image

JAVA API

        平时API听多了,但是或许并不了解,这里做下简要解释。一个操作系统会提供很多API接口让程序员使用计算机的硬件资源,这是系统API,这里涉及到一个POSXI的概念,POSIX表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。因为遵循POSXI标准的操作系统,所定义的操作系统API都相同,所以开发程序的时候,使用的API在名称参数上都可以兼容,所以换一个系统,不需要重新编写代码。POSIX是针对API的标准,即针对API的函数名,返回值,参数类型等。POSIX兼容也就指定这些接口函数兼容,但是并不管API具体如何实现。

        Java api:就是用java语言编写的功能代码,为访问主机上的本地资源,Java api调用了本地方法(操作系统API),直接通过内核请求调用相关内核函数。而后将功能相似的这些代码归类,组成java api类库。

以linux编程为例:我们编写linux用户程序的时候,是不能直接调用内核里面的函数的,内核里面的函数位于进程虚拟地址空间里面的内核空间,用户空间函数及函数库都处于进程虚拟地址空间里面的用户空间,用户空间调用内核空间的函数只有一个通道,这个通道就是系统调用指令,所以通常要调用glibc等库的接口函数(C语言的API),glibc也是用户空间的,但glibc自己实现了调用特殊的宏汇编系统调用指令进行cpu运行状态的切换,把进程从用户空间切换到内核空间。

        image

JVM 内存结构

image

    java中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域main memory,而每个线程又单独的有自己的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交由线程处理。

    程序计数器(Program Counter Register):由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器

    Java 虚拟机栈(Java Virtual Machine Stacks):每个放在被执行的时候都会同时创建一个栈帧用于存当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double),操作数栈,动态链接,方法出口等信息。虚拟内存栈就是我们经常讲的“栈”。其中局部变量表所需内存是在编译期完成分配。

    方法区(Method Area):与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。也称为持久代(Permanet Generation)。

    Java 堆(Java Heap):是Java 虚拟机所管理的内存中最大的一块。它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配。Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(Garbage Collected Heap)。

    本地方法栈:与虚拟机栈类似,区别在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机使用Native方法(系统接口)服务。

WEB CGI

        早期的web只能实现静态的页面,如果我们需要一种效果,就是我们向服务器请求时想让web服务器现场处理并将处理过的数据结果返回给我们,该如何实现呢。

        第一种方式:开发一个程序,接收用户请求,解析请求内容,查找相关数据进行计算处理,将处理结果封装成响应报文返回给用户。

        第二种方式:既然已经存在web服务器了,那没必要重新开发程序来处理HTTP协议的东西,只需要开发另一种方式,让计算机能够将处理后的数据,发送给web服务器,服务器再返回给用户

        于是CGI协议就产生了,web服务器接收到请求,可是它自身无法解决请求之中需要经过计算处理的内容,那样服务器就去找帮手,找个能处理这个内容的其他程序,这个其他程序通过一种方式(CGI)和服务器进行交流,处理好之后将结果送给web服务器。

image

上图源自--《Servlet JSP深入详解 基于Tomcat的Web开发》.(孙鑫)

后来看到一个对CGI很形象的解释

image

Serlvet与Servlet容器

        当java想实现CGI这样的功能时,因为java代码运行在jvm中,而jvm是没有办法直接跟web服务器进行交流的,所以Servlet就出现了。

image

上图源自--WEB请求处理三:Servlet容器请求处理

        既然java作为编程语言,那么我们可以开发自己想要的功能,我们开发一个程序,使之能够与web服务器进行交互。所以java写了一个servlet类,这个类可以实例化为servlet程序,这个程序可以接受来自web服务器的请求并处理。那问题又来了, 如果多个web请求过来,仅仅一个Servlet程序是不够的,而且请求来了如何对java代码编译呢,于是乎就在外层增加一个管理功能的容器(这里纯属个人臆想),所以如果把Servlet类库完整实现了,那就是Servlet容器。这个容器的作用是什么呢?

1、利用容器提供的方法,你能轻松的让servlet与web服务器对话,而不用自己建立serversocket、监听某个端口、创建流等等。容器知道自己与web服务器之间的协议,所以你的servlet不用担心web服务器(如Apache)和你自己的web代码之间的API,只需要考虑如何在servlet中实现业务逻辑(比如从数据库或者磁盘中获取数据并处理)。

2、多线程支持:容器会自动为它所接收的每个servlet请求创建一个新的java线程。针对用户的请求,如果servlet已经运行完相应的http服务方法,这个线程就会结束。

3、生命周期管理:servlet容器控制着servlet的生与死,它负责加载类、实例化和初始化servlet,调用servlet方法,以及使servlet实例被垃圾回收。

        image

        Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序(服务器响应)之间的中间层,位于Web 服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。客户端发送请求至服务器;服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器;服务器将响应返回客户端。       

        servlet就是一个组件,需要部署到servlet容器才能运行。servlet容器为servlet提供网络相关的服务:即servlet容器为将请求中的相关数据解析出来,并且封装到请求对象(request)里面,这样一来,servlet就不需要理解http协议(只需要调用request对象的相关方法即可获取数),另外,当servlet处理请求完毕,只需要将结果写到响应对象(response)里面,servlet容器会自动将response对象中的数据打包,发送给浏览器。

java servlet 简单代码实现
Java Servlet与CGI (Common Gateway Interface 公共网关接口)的比较:

  与传统的CGI和许多其他类似CGI的技术相比,Java Servlet具有更高的效率,更容易使用,功能更强大,具有更好的可移植性,更节省投资。在未来的技术发展过程中,Servlet有可能彻底取代CGI。

  在传统的CGI中,每个请求都要启动一个新的进程,如果CGI程序本身的执行时间较短,启动进程所需要的开销很可能反而超过实际执行时间。而在Servlet中,每个请求由一个轻量级的Java线程处理(而不是重量级的操作系统进程)。

  在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中重复装载了N次;而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。在性能优化方面,Servlet也比CGI有着更多的选择。

JSP

        使用Servlet可以实现java程序和web服务器的交互,但是Servlet和CGI一样存在一个问题,Servlet程序在返回结果的时候必须连带HTML标签一起返回,所以负责格式显示的HTML代码和负责数据产生的Java代码混在一起了,程序员和页面编辑人员无法各自实现自己的工作,就要求java程序员必须要了解HTML显示效果。所以就有了JSP技术产生,有了JSP一个web请求的执行流程如下。

        image

其实JSP也是java的一个类库而已,要想写出的JSP代码能够被识别,这时候就需要一个JSP容器负责来解析。JSP代码最终会被编译成Servlet,然后再由Servlet处理请求。一个JSP页面包含了JSP规范的java代码(元素)和HTML标签(数据模板),元素则交给JSP容器处理,模板数据直接返回给客户端。

TOMCAT

Tomcat是一个免费的开源的Serlvet容器,实现了Servlet和Jsp规范的一个产品。tomcat的体系结构如下

解析Tomcat内部结构和请求过程

image

tomcat组成及原理

image

posted on 2016-08-18 15:25  彼岸船夫  阅读(659)  评论(0编辑  收藏  举报

导航