Java Web开发的基础内容:
- Servlet:增加了几个限制的Java类,所以开发一个Servlet并不复杂;然后就是把Servlet部署到web服务器上(Tomcat这个老人家现在身体依然硬朗!),然后就等待客户的请求就可以了
Servlet的三层部署图
- javabean
- jsp
采用MVC(model,view,controller)结构组合servlet、javabean和jsp的标准Javaweb结构
MVC功能图
一、基础知识:
- Java Web是以线程为单位管理请求,处理能力更强,占用的资源更少
- CGI是以进程为单位管理请求的,Servlet解决相同数量的请求,却占用较少的系统资源
- Java Web核心的组件就是Servlet
CGI的资源占用图
java web中的servlet资源图
1.HTTP协议(超文本传输协议):一种主流B/S架构中应用的通信协议
- 无状态:服务端不会记录客户端每次提交的请求,服务器一旦响应客户端之后,就会结束本次的通信过程。客户端下一次的请求是一个新的连接,和上一次通信没有任何关系
- 简单灵活:HTTP是基于请求(request)和响应(response)的模型
- 支持客户端与服务端:支持主流的B/S架构的通信以及C/S架构的通信- C/S架构可选的协议有多种,例如:TCP/IP,UDP,HTTP,而B/S架构通常只支持HTTP协议
2.服务器:通常由硬件和软件部分构成,统一对用户提供多种不同的服务
- 硬件:包括响应的CPU、内存、磁盘等等
- 软件:包括操作系统、运行环境、服务器软件、数据库等等
1)web服务器:
- web服务器是提供服务端程序运行的一个环境,它本身也是一个软件- 例如:将我们编写HTML文件放入到web服务器中,那么外界就可以通过浏览器访问我们的html页面
- 常见的web服务器有Apache,Tomcat、Jetty、Nginx等等- Tomcat、Jetty这些web服务器更准确的说是一个Servlet容器
3.JavaWeb项目结构!!!
项目根目录,例如:myweb、ch01通常存放静态资源文件(如:html等等)WEB-INF这个目录是当前项目私有的一个文件夹,只能提供给项目内部访问,对于客户端来说是访问不到了,通常这个目录下存放的是Java源代码、编译后的字节码文件以及Servlet的核心配置文件web.xmlsrc存放java源代码的目录classes存放编译后的字节码文件liblib目录存放当前项目所需要的jar文件JSP用于存放JSP动态页面web.xml项目的配置文件,用于配置Servlet的请求映射、过滤器、监听器等等信息。每一个web项目都对应一个web.xml配置文件META-INF****配置应用程序、扩展程序、类加载服务等等
二、servlet和jsp对比
**1. servlet 和 jsp 的区别: **
Servlet在Java代码中可以通过HttpServletResponse对象动态输出HTML内容
JSP是在静态HTML内容中嵌入Java代码,然后Java代码在被动态执行后生成HTML内容
jsp经编译后就变成了Servlet(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)
jsp更擅长表现于页面显示,servlet更擅长于逻辑控制
Servlet中没有内置对象,内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到
Jsp是Servlet的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,Jsp中的Java脚本如何镶嵌到一个类中,由Jsp容器完成
Servlet则是个完整的Java类,这个类的Service方法用于生成对客户端的响应
对于静态HTML标签,Servlet都必须使用页面输出流逐行输出
2. servlet 和 jsp 的各自特点:
- Servlet虽然能够很好地组织业务逻辑代码,但是在Java源文件中,因为是通过字符串拼接的方式生成动态HTML内容,这样就容易导致代码维护困难、可读性差
- JSP虽然规避了Servlet在生成HTML内容方面的劣势,但是在HTML中混入大量、复杂的业务逻辑
3. MVC模式使用 servlet 和 jsp:
Servlet只负责业务逻辑部分,而不会生成HTML代码
JSP中不会充斥着大量的业务代码,这样能大提高了代码的可读性和可维护性
** MVC模式(Model-View-Controller):**软件工程中的一种**软件架构模式,分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)**
Controller(Servlet)——负责转发请求,对请求进行处理
View(JSP)——负责界面显示
Model——业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现
- Web浏览器发送HTTP请求到服务端,然后被Controller(Servlet)获取并进行处理(例如参数解析、请求转发)
- Controller(Servlet)调用核心业务逻辑——Model部分,获得结果
- Controller(Servlet)将逻辑处理结果交给View(JSP),动态输出HTML内容
- 动态生成的HTML内容返回到浏览器显示
三、servlet
- Java Servlet 是运行在 Web 服务器或应用服务器上的程序
- 是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层
- 使用 Servlet,以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页
1. servlet的优势(与CGI相比):
- 性能明显更好(相同数量请求,占用系统资源更少)
- Servlet 在 Web 服务器的地址空间内执行;这样它就没有必要再创建一个单独的进程来处理每个客户端请求
- Servlet 是独立于平台的,因为它们是用 Java 编写的
- 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的
- Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互
2.Servlet的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化- init 方法被设计成只调用一次,用于一次性初始化,就像 Applet 的 init 方法一样- 它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用- Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载
- Servlet 调用 service() 方法来处理客户端的请求- service() 方法是执行实际任务的主要方法- Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端- 每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务;service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法
- Servlet 通过调用 destroy() 方法终止(结束)- destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用- destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动- 在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的
例:
第一次请求:
继续请求:
3.servlet相关面试题
1)不同的用户同时对同一个业务(如注册)发出请求,那这个时候容器里产生的有是几个servlet实例呢?(怎样理解Servlet的单实例多线程?)!!!
- 只有一个servlet实例;一个servlet是在第一次被访问时加载到内存并实例化的
- 同样的业务请求共享一个servlet实例;不同的业务请求一般对应不同的servlet
- 由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题
2)JSP的中存在的多线程问题
- 当客户端第一次请求某一个JSP文件时,服务端把该JSP编译成一个CLASS文件,并创建一个该类的实例,然后创建一个线程处理CLIENT端的请求
- 如果有多个客户端同时请求该JSP文件,则服务端会创建多个线程。每个客户端请求对应一个线程。以多线程方式执行可大大降低对系统的资源需求,提高系统的并发量及响应时间
3)对JSP中可能用的的变量说明
- 实例变量: 实例变量是在堆中分配的,并被属于该实例的所有线程共享,所以不是线程安全的
- JSP系统提供的8个类变量:- JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是线程安全的(因为每个线程对应的request,respone对象都是不一样的,不存在共享问题)- APPLICATION在整个系统内被使用,所以不是线程安全的
- 局部变量: 局部变量在堆栈中分配,因为每个线程都有它自己的堆栈空间,所以是线程安全的
- 静态类: 静态类不用被实例化,就可直接使用,不是线程安全的
- 外部资源: 在程序中可能会有多个线程或进程同时操作同一个资源(如:多个线程或进程同时对一个文件进行写操作).此时也要注意同步问题
4)Servlet单实例多线程机制:
- Servlet采用多线程来处理多个请求同时访问
- servlet依赖于一个线程池来服务请求;线程池实际上是一系列的工作者线程集合。Servlet使用一个调度线程来管理工作者线程
- 当容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。
- 当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet
- 当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行
- Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目
5)如何开发线程安全的Servlet
- 实现 SingleThreadModel 接口- 该接口指定了系统如何处理对同一个Servlet的调用- 如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。这种方法只要将前面的Concurrent Test类的类头定义更改为:
Public class Concurrent Test extends HttpServlet implements SingleThreadModel {
…………
}
6)同步对共享数据的操作
- 使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段
- 避免使用实例变量- 本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的
7)Struts1 Action和Struts2的Action辨析
- Struts2 Action是原型,非单实例的;会对每一个请求,产生一个Action的实例来处理- Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)
- Struts1 Action是单实例的,mvc的controller也单实例的- 因此Struts1 Action和mvc的controller开发时要求必须是线程安全的,因为仅有Action的一个实例来处理所有的请求;单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心- Struts1 Action资源必须是线程安全的或同步的
- Struts1 Action,Spring的Ioc容器管理的bean默认是单实例的
- 当Spring管理Struts2 Action时,bean默认是单实例的,可以通过配置参数将其设置为原型(scope="prototype )
四、JDBC数据库连接池
1. 为什么要使用连接池:
在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤:
- 在主程序(如servlet、beans)中建立数据库连接
- 进行sql操作
- 断开数据库连接
这种模式存在的问题:
- 普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证用户名和密码(得花费0.05s~1s的时间);需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃
- 对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库
- 这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃
连接池本质上是构建一个容器,容器来存储创建好的线程、http连接、数据库连接、netty连接等
2. 连接池技术核心:
- 连接或者说创建的资源复用
3.使用连接池的好处:
- 连接复用:通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销
- 对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用
- 连接池还有一个副作用就是实现了高可用,在微服务场景下一个连接不可用,那么再从netty连接池中取出一个进行使用,避免了连接不可用问题
各个连接池构建、使用管理详细过程大概分成以下三部分:
- 首先初始化连接池:根据设置相应参数:连接池大小、核心线程数、核心连接数等参数,初始化创建数据库、http、netty连接以及jdk线程
- 连接池使用:前边初始化好的连接池、线程池,直接从连接池、线程中取出资源即可进行使用,使用完后要记得交还连接池、线程池,通过池容器来对资源进行管理
- 对于连接池维护:连接池、线程池来维护连接、线程状态,不可用连接、线程进行销毁,正在使用连接、线程进行状态标注,连接、线程不够后并且少于设置最大连接、线程数,要进行新连接、线程创建
4.连接池的实现
- 数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取方法和返回方法。
- 外部使用者可通过 getConnection 方法获取连接,使用完毕后再通过 close 方法将连接返回,此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备
- Java 中有一个 DataSource 接口, 数据库连接池就是 DataSource 的一个实现
5.数据库连接池
1)定义及理解:
- 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”;预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去
- 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
- 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中- 数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。- 连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中
** 2)数据库连接池技术的优点**
- 资源重用(复用):****由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销;在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性
- 更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间
- 新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源
- 统一的连接管理,避免数据库连接泄露:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露
3)两种开源的数据库连接池:
- JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:- DBCP 数据库连接池- C3P0 数据库连接池
- DataSource 通常被称为数据源,也可称为连接池,它包含连接池和连接池管理两个部分
- 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可
- 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但上面的代码并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池
版权归原作者 我爱豆子 所有, 如有侵权,请联系我们删除。