java web-------------jsp,servlet原理

一、jsp文件:
jsp文件实质上是一个java文件,不管你在编译器中如何编写jsp页面,java虚拟机最后都会编译成.java文件;jsp其实就是一个servlet,一个servlet完全可以修改成一个jsp页面,只不过是在实际开发中把后台和前台分开使用,后台servlet 前台jsp页面。
二、jsp执行原理:
jsp实质是java中的一个类对象(单例对象),它继承HttpJspBase类 实现JspSourceDependent接口,在jsp类中写的html代码,都以out.write()方法写入到页面,如果写java代码则正常写到类中(tomcat根据输入的如果是java代码他就会执行,不是java代码的话原样输出。)
《此案例讲述jsp的全局变量的线安全问题:(实质是全局变量是定义在共享内存(堆内存)中)可供线程共享,但cpu给每一个线程的时间和顺序是无序的,在多个线程同时访问时有些线程可能执行不完,下一个线程就执行了,所以造成的结果就不正确!》
三、jsp执行:
<%int i=10%>(局部变量的定义)
<%!int i=10%>(成员变量的定义)---------》生成全局的类,变量,方法。
&执行的安全问题:
在jsp中写:

<%!int i=10 %>
<%=i++%>

结果:50人同时访问jsp应该是60,但是返回的永远比50小。如果将int i 改成局部的变量,就会避免这个问题。
原因是定义成全局变量时,定义的变量在方法外部,而实际上50人同时访问时是访问的方法,所以每个人的访问都是一个线程来执行i++的方法,这就暴露出线程的安全问题。
其实线程执行的过程(以本案例为例):
1、先读取变量的值
2、copy变量的值到当前线程内存中
3、在当前线程内存中执行方法的计算
4、将计算后的结果写入到主内存中
相当于定义的全局变量(<%!int i=10 %>)储存在主内存(堆内存)中,而每个线程中都有自己的内存空间,在线程访问时是没有顺序的,cpu随机安排,如果线程同时访问,则线程同时拿到全局变量,而cpu只执行一个线程,加入t1线程时买没执行完,后边的线程就再执行,这样就造成线程的安全问题,每个线程执行的步骤很多,而cpu给每个线程的时间是无序的,就造成了线程安全问题,如果此案例访问的越多结果越明显,但cpu的计算速度越快这种结果越小。
据此出现的问题解决的方法:
1、可以在执行的方法代码块上加一个同步锁。 -----》但造成后果是访问时速度非常慢,但绝对不会出错!
2、全局变量定义为局部变量。---------》永远不会出现线程安全问题。
所以如果出现线程安全问题基本上就是
1、定义成员变量被多个线程使用。
2、jsp类为单例模式的也会造成线程安全问题,如果是多例的就会避免线程安全问题。

四、jsp中的三大指令,七大动作,九大内置对象:

1、三大指令:

page指令:page 指令指明与JSP容器的沟通方式
			<%@ page 
				 language=“Java”           选择编码语言 
				 import=“importList”      导入java类库(唯一可以重复使用的属	性,其他属性最多只能使用一次) 
				 contentType=“contentTyepInfo”   内容的类型 
				 session=“true|false”            是否开启Session 
				 isThreadSafe=“true|false”    是否线程安全,默认为true 
				info=“infoText” 
				errorPage=“errorPageUrl”     指定错误页面:如果发生异常,则会跳到这个错误页面 
				 isErrorPage=“true|false”     指定当前这个页面是否为错误页面。如果其他的页面发生错误,就会调到这里来。 %>
include指令:是在JSP页面被转换成Servlet之前将指定的文件包含进来。这种特性允许你创建可重用的导航栏、联系人信息部分、页面计数等。
									(重复利用的理解:比如说,可能有多页面都需要用到某个标题页面,就可以把这个公共的标题页面使用include指令包含进来,然后在其他的页面中直接导入标题页面就行了)
	==》include指令共有两种形式:
			1、静态导入(多个页面编译成一个页面,耦合性高,解析执行速度快):include静态包含,只能包含静态的资源,编译后形成一个文件。合起来只形成一个.java文件,最后编译为一个.class文件。
			2、动态导入(生成两个java源文件,不会互相干扰):动态包含的主要区别在于,其每个页面单独生成JAVA源文件,不会互相干扰。

面试:静态导入时是形成一个文件,定义相同的变量就会报错,而动态就不会报错因为实质上是形成了两个文件。

taglib指令:
	在JSP页面中使用第三方的标签库时,需要使用taglib指令来“导包”。

2、七大动作:

jsp:forward(请求转发);
				格式:<jsp:forward page="content.jsp"></jsp:forward>  ---------------》if(true){_jspx_page_context.forward("content.jsp"); return;} 
				可以看出底层是调用了一个请求转发,同时如果调用成功,会直接return 掉,后续代码不继续执行。
jsp:plugin(插入插件) ;
						格式:<jsp:plugin type="" code=""></jsp:plugin>	
							type=”bean | applet” .将被执行的插件对象的类型,你必须得指定这个是Bean还是applet,因为这个属性没有缺省值.
							code=”classFileName” 将会被Java插件执行的Java 
							Class的名字,必须以.class结尾。这个文件必须存在于codebase属性指定的目录中.
							codebase=”classFileDirectoryName” 将会被执行的Java 
							Class文件的目录(或者是路径),如果你没有提供此属性,那么使用的jsp文件的目录将会被使用.
							name=”instanceName” 这个Bean或applet实例的名字,它将会在Jsp其它的地方调用.
							archive=”URIToArchive, …” 
							一些由逗号分开的路径名,这些路径名用于预装一些将要使用的class,这会提高applet的性能.
							align=”bottom | top | middle | left | right” 图形,对象,Applet的位置,有以下值:

							bottom
							top
							middle
							left
							right
							height=”displayPixels” width=”displayPixels” 
							Applet或Bean将要显示的长宽的值,此值为数字,单位为象素.
							hspace=”leftRightPixels” vspace=”topBottomPixels” 
							Applet或Bean显示时在屏幕左右,上下所需留下的空间,单位为象素.
							jreversion=”JREVersionNumber | 1.1” Applet或Bean运行所需的Java Runtime 
							Environment (JRE) 的版本. 缺省值是 1.1.
							nspluginurl=”URLToPlugin” Netscape 
							Navigator用户能够使用的JRE的下载地址,此值为一个标准的URL,如http://www.aspcn.com/jsp
							iepluginurl=”URLToPlugin” 
							IE用户能够使用的JRE的下载地址,此值为一个标准的URL,如http://www.aspcn.com/jsp
jsp:usebean(引入javabean);
格式:<jsp:usebean id="对象名" class="包名.类名" scope="作用范围(request/page/application/session)"></jsp:usebean>用于引入javabean,通常配合setProperty以及setProperty使用
jsp:setProperty(在bean中设置一个或多个属性);
						格式:<jsp:setProperty name="javaBean对象id" property="javaBean对象属性名(javabean引入的方法名,可填入 * 来引入全部方法" </jsp:setProperty>
用于设置属性,只有设置了属性后,才可以获取相应的属性。 
可使用通配符 * ,来将引入的javabean中的全部属性设置。就相当于可以调用usebean中引入的java类的全部属性。
jsp:getProperty(获取属性);
	格式:<jsp:getProperty name="javaBean对象id" property="javaBean对象属性名" />
jsp:include(动态导入页面);
	格式:<jsp:include page="fileURL"></jsp:include> 
	注意:动态包含的主要区别在于,其每个页面单独生成JAVA源文件,不会互相干扰。
jsp:param(传递参数);
	格式:<jsp:param name="paramName" value="paramValue"/>  其中,name为与属性相关联的关键词,value为属性的值。

3、九大内置对象:九大内置对象,包括
4大作用域对象(pageContext、request、session、application)[作用域范围从低到高]
3大对象(page[页面对象]、config[配置对象]、exception[例外对象])
2大输出对象(out[输出对象]、response[响应对象])

request(请求对象);
“request” 对象代表的是来自客户端的请求,例如我们在FORM表单>中填写的信息等,是最常用的对象。
关于它的方法使用较多的是getParameter、getParameterNames,getParameterValue,通过调用这几个方法来获取请求对象中所包含的参数的值.
response(请求对象):
		“response” 对象代表的是对客户端的响应,也就是说可以通过“response”对象来组织发送到客户端的数据。
		但是由于组织方式比较底层,所以不建议使用,需要向客户端发送文字时直接使用“out” 对象即可。
session(请求对象):
		“session” 对象代表服务器与客户端所建立的会话,当需要在不同的JSP页面中保留客户信息的情况下使用,比如在线购物、客户轨迹跟踪等。
application(请求对象):
	“application” 对象负责提供应用程序在服务器中运行时的一些全局信息,常用的方法有getMimeType和getRealPath等。
out(请求对象):
“out” 对象代表了向客户端发送数据的对象,与“response” 对象不同,通过“out” 对象发送的内容将是浏览器需要显示的内容,是文本一级的,可以通过“out” 对象直接向客户端写一个由程序动态生成HTML文件。常用的方法除了print和println之外,还包括clear、clearBuffer、flush、getBufferSize和getRemaining,这是因为“out” 对象内部包含了一个缓冲区,所以需要一些对缓冲区进行操作的方法。
config(请求对象):
“config” 对象提供一些配置信息,常用的方法有getInitParametergetInitParameterNames,以获得Servlet初始化时的参数。
page(请求对象)
“page” 对象代表了正在运行的由JSP文件产生的类对象,一般不建议使用。
exception(请求对象):
“exception” 对象则代表了JSP文件运行时所产生的例外对象,此对象不能在一般JSP文件中直接使用,而只能在使用了“<%@ page isErrorPage=”true “%>”的JSP文件中使用 
pageContext(请求对象);
封装了当前jsp页面的运行信息,它提供了返回jsp页面的其他隐式对象的方法 : 
 getRequest(), getResponse(), getPage() 
 getServletContext() , getApplication(), getOut() 
 getSession(), getException(), getServletConfig()

java servlet 工作原理:
Servlet它可以分为3个阶段;初始化,运行,销毁。
初始化阶段:
1,Servlet容器加载servlet类,把servlet类的.class文件中的数据读到内存中。
2,然后Servlet容器创建一个ServletConfig对象。ServletConfig对象包含了Servlet的初始化配置信息。
3,Servlet容器创建一个servlet对象。
4,Servlet容器调用servlet对象的init方法进行初始化。
运行阶段:
当servlet容器接收到一个请求时,servlet容器会针对这个请求创建servletRequest servletResponse对象。
然后调用service方法。并把这两个参数传递给service方法。Service方法通过servletRequest对象获得请求的信息。
并处理该请求。再通过servletResponse对象生成这个请求的响应结果。然后销毁servletRequest和servletResponse对象。
我们不管这个请求是post提交的还是get提交的,最终这个请求都会由service方法来处理。
销毁阶段:
当Web应用被终止时,servlet容器会先调用servlet对象的destrory方法,
然后再销毁servlet对象,同时也会销毁与servlet对象相关联的servletConfig对象。
我们可以在destroy方法的实现中,释放servlet所占用的资源,如关闭数据库连接,关闭文件输入输出流等。
在这里该注意的地方:在servlet生命周期中,servlet的初始化和和销毁阶段只会发生一次,而service方法执行的次数则取决于servlet被客户端访问的次数

猜你喜欢

转载自blog.csdn.net/qq_42891281/article/details/105126424