JSP的运行内幕_MySQL

Jun 01, 2016 pm 02:07 PM
jsp tomcat 方法 ラベル 解析する 走る


经常有朋友问起,JSP和Servlet之间有什么区别,两者之间又有什么联系?其实Servlet技术的出现时间很早,是当时为了Java的服务器端应用而开发的。大家都知道Applet是应用小程序,Servlet就是服务器端小程序了。但在Microsoft公司的ASP技术出现后,使用Servlet进行响应输出时一行行的输出语句就显得非常笨拙,对于复杂布局或者显示页面更是如此。JSP就是为了满足这种需求在Servlet技术之上开发的。可见,JSP和Servlet之间有着内在的血缘关系,在学习JSP时,如果能够抓住这种联系,就能更深刻地理解JSP的运行机理,达到事半功倍的效果。

本文将通过对一个JSP运行过程的剖析,深入JSP运行的内幕,并从全新的视角阐述一些JSP中的技术要点。

HelloWorld.jsp


我们以Tomcat 4.1.17服务器为例,来看看最简单的HelloWorld.jsp是怎么运行的。

代码清单1:HelloWorld.jsp

HelloWorld.jsp
String message = "Hello World!";
%>




   这个文件非常简单,仅仅定义了一个String的变量,并且输出。把这个文件放到Tomcat的webapps\ROOT\目录下,启动Tomcat,在浏览器中访问 http://localhost:8080/HelloWorld.jsp ,浏览器中的输出为“HelloWorld!”

  让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的HelloWorld_jsp.java,这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件:

  代码清单2:HelloWorld_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class HelloWorld_jsp extends HttpJspBase {
......
public void _jspService(HttpServletRequest request,
HttpServletResponse response)throws java.io.IOException, ServletException
{
JspFactory _jspxFactory = null;
javax.servlet.jsp.PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;

try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");

  包含定制标签的index.jsp

  Struts1.1b的下载地址是 http://jakarta.apache.org/struts/index.html 。将下载的包解压,在webapps目录下可以找到struts-example.war。将该War包拷贝到Tomcat的webapps目录下,Tomcat会自动安装此应用包。在浏览器中通过 http://localhost:8080/struts-example 访问struts-example应用,将显示应用的首页(见图1)。

  图一 应用的首页

  代码清单4:index.jsp







<message key="index.title"></message>



……





   我们仅以index.jsp中的标签的解析为例进行分析,看容器是怎样把这个自定义标签解析成HTML输出的。上面代码省略了页面的其它显示部分。首先,查看上面浏览器中页面的源文件:



MailReader Demonstration Application (Struts 1.0)


……





   可见,容器已经把替换成一个字串,显示为页面的标题。

  解析过程

  那么,JSP容器是怎样完成解析的呢?查看在工作目录jakarta-tomcat-4.1.17\work\Standalone\localhost\struts-example下解析后的index_jsp.java文件:

  代码清单5:index_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class index_jsp extends HttpJspBase {
//为所有的定制标签定义处理器池类的引用
private org.apache.jasper.runtime.TagHandlerPool ;
_jspx_tagPool_bean_message_key;
……
//页面类构造方法
public index_jsp() {
_jspx_tagPool_bean_message_key =
new org.apache.jasper.runtime.TagHandlerPool();
……
}

public void _jspService(HttpServletRequest request,
   HttpServletResponse response)
   throws java.io.IOException, ServletException {
……
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this,
   request, response,null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
……
if (_jspx_meth_html_html_0(pageContext))
return;
……
}
//页面在处理退出时释放所有定制标签的属性
public void _jspDestroy() {
_jspx_tagPool_bean_message_key.release();
……
}
}



   生成的index_jsp.java继承于org.apache. jasper.runtime.HttpJspBase。研究这个文件为我们了解定制标签的运行机理提供了途径。

  从上面可以看出,Tomcat在解析一个JSP页面时,首先为每一个定制标签定义并实例化了一个TagHandlerPool对象。页面的处理方法覆盖父类的_ jspService()方法,_jspService方法首先初始化环境,为内置对象赋值。由于index.jsp页面整体由一个标签包裹,Tomcat对每一个标签都产生一个私有方法加以实现。标签的处理方法是_jspx_meth_html_html_0()。这个方法的命名规范大家也可以从这里看出,就是“_jspx_meth + 标签的前缀 + 标签名 + 该标签在JSP页面同类标签中出现的序号”。其它标签都被包含在该标签中,所以其它标签在_jspx_meth_html_html_0()方法中进行解析。具体的代码实现请参见赛迪网 http://linux.ccidnet.com 期刊浏览2003年第6期。

  在_jspx_meth_html_html_0()方法中,首先从_jspx_tagPool_html_html_locale池中得到一个org.apache.struts.taglib.html.HtmlTag的实例,然后设置这个tag实例的页面上下文及上级标签,由于html:html标签是页面的最顶层标签,所以它的parent是null。然后对该标签的内容进行解析。HTML代码直接输出,下面主要看看标签之间包含的标签的解析。对bean:message标签的解析类似于html:html,Tomcat也将其放入一个单独的方法_jspx_meth_bean_message_0()中进行。

  bean:message标签的解析

  代码清单7:_jspx_meth_bean_message_0()方法片断

//对message定制标签的处理方法
private boolean _jspx_meth_bean_message_0(
javax.servlet.jsp.tagext.Tag _jspx_th_html_html_0,
javax.servlet.jsp.PageContext pageContext) throws Throwable {
JspWriter out = pageContext.getOut();
/* ---- bean:message ---- */
org.apache.struts.taglib.bean.MessageTag
_jspx_th_bean_message_0 =
(org.apache.struts.taglib.bean.MessageTag)
_jspx_tagPool_bean_message_key.get(
org.apache.struts.taglib.bean.MessageTag.class);
_jspx_th_bean_message_0.setPageContext(pageContext);
_jspx_th_bean_message_0.setParent(_jspx_th_html_html_0);
_jspx_th_bean_message_0.setKey("index.title");
int _jspx_eval_bean_message_0 = _jspx_th_bean_message_0.doStartTag();
if (_jspx_th_bean_message_0.doEndTag()== javax.servlet.jsp.tagext.Tag.SKIP_PAGE)
return true;
_jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0);
return false;
}



   同样,对html:bean也需要从池中得到一个标签类的实例,然后设置环境。这里不再赘述。我们只专注对MessageTag定制标签类特殊的处理部分。定制标签类的开发不在本文讨论范围之内。在index.jsp中定义了一个bean:message标签,并设置了一个属性:。Tomcat在解析时,调用MessageTag对象的key属性设置方法setKey(),将该属性置入。然后调用MessageTag的doStartTag()和doEndTag()方法,完成解析。如果doEndTag()方法的返回值为javax.servlet.jsp.tagext.Tag. SKIP_PAGE,表明已经完成解析,返回true,Tomcat将立即停止剩余页面代码的执行,并返回。否则把该MessageTag的实例放回池中。

  标签类对象实例的池化

  为了提高运行效率,Tomcat对所有的定制标签类进行了池化,池化工作由org.apache.jasper. runtime.TagHandlerPool类完成。TagHandlerPool类主要有两个方法,代码如下:

  代码清单8:TagHandlerPool.java

public class TagHandlerPool {
private static final int MAX_POOL_SIZE = 5;
private Tag[] handlers;
public synchronized Tag get(Class handlerClass) throws JspException {……}
public synchronized void reuse(Tag handler) {……}
}



   TagHandlerPool简单地实现了对标签类的池化,其中MAX_POOL_SIZE是池的初始大小,handlers是一个Tag的数组,存储标签类的实例。get(Class handlerClass)得到一个指定标签类的实例,如果池中没有可用实例,则新实例化一个。reuse(Tag handler)把handler对象放回池中。

  至此,我们对JSP在容器中的运行过程已经了然于胸了。虽然每种JSP容器的解析结果会有差异,但其中的原理都雷同。对于编写JSP应用,我们并不需要干涉容器中的运行过程,但如果你对整个底层的运行机制比较熟悉,就能对JSP/Servlet技术有更深的认识。
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WeChat で削除された連絡先を回復する方法 (簡単なチュートリアルでは、削除された連絡先を回復する方法について説明します) WeChat で削除された連絡先を回復する方法 (簡単なチュートリアルでは、削除された連絡先を回復する方法について説明します) May 01, 2024 pm 12:01 PM

残念ながら、WeChat は広く使用されているソーシャル ソフトウェアであり、何らかの理由で特定の連絡先を誤って削除してしまうことがよくあります。ユーザーがこの問題を解決できるように、この記事では、削除された連絡先を簡単な方法で取得する方法を紹介します。 1. WeChat の連絡先削除メカニズムを理解します。これにより、削除された連絡先を取得できるようになります。WeChat の連絡先削除メカニズムでは、連絡先がアドレス帳から削除されますが、完全には削除されません。 2. WeChat の組み込みの「連絡先帳復元」機能を使用します。WeChat には、この機能を通じて以前に削除した連絡先をすばやく復元できる「連絡先帳復元」機能が用意されています。 3. WeChat 設定ページに入り、右下隅をクリックし、WeChat アプリケーション「Me」を開き、右上隅にある設定アイコンをクリックして設定ページに入ります。

Tomcat で複数のプロジェクトをデプロイする方法 Tomcat で複数のプロジェクトをデプロイする方法 Apr 21, 2024 am 09:33 AM

Tomcat を介して複数のプロジェクトをデプロイするには、プロジェクトごとに webapp ディレクトリを作成してから、次の操作を行う必要があります。 自動デプロイ: webapp ディレクトリを Tomcat の webapps ディレクトリに配置します。手動デプロイメント: Tomcat のマネージャー アプリケーションにプロジェクトを手動でデプロイします。プロジェクトがデプロイされると、そのデプロイメント名 (例: http://localhost:8080/project1) でアクセスできるようになります。

Tomcatでの同時接続数を確認する方法 Tomcatでの同時接続数を確認する方法 Apr 21, 2024 am 08:12 AM

Tomcat の同時接続数を確認する方法: Tomcat Manager ページ (http://localhost:8080/manager/html) にアクセスし、ユーザー名とパスワードを入力します。左側のナビゲーション バーで [ステータス] -> [セッション] をクリックすると、ページの上部に同時接続数が表示されます。

Tomcat Web サイトのルート ディレクトリはどこですか? Tomcat Web サイトのルート ディレクトリはどこですか? Apr 21, 2024 am 09:27 AM

Tomcat Web サイトのルート ディレクトリは Tomcat の webapps サブディレクトリにあり、Web アプリケーション ファイル、静的リソース、および WEB-INF ディレクトリを保存するために使用されます。これは、Tomcat 構成ファイルで docBase 属性を検索することで見つかります。

携帯電話の文字サイズの設定方法(携帯電話の文字サイズを簡単に調整できます) 携帯電話の文字サイズの設定方法(携帯電話の文字サイズを簡単に調整できます) May 07, 2024 pm 03:34 PM

携帯電話が人々の日常生活において重要なツールになるにつれて、フォント サイズの設定は重要なパーソナライゼーション要件になりました。さまざまなユーザーのニーズを満たすために、この記事では、簡単な操作で携帯電話の使用体験を向上させ、携帯電話のフォントサイズを調整する方法を紹介します。携帯電話のフォント サイズを調整する必要があるのはなぜですか - フォント サイズを調整すると、テキストがより鮮明で読みやすくなります - さまざまな年齢のユーザーの読書ニーズに適しています - フォント サイズを使用すると、視力の悪いユーザーにとって便利です携帯電話システムの設定機能 - システム設定インターフェイスに入る方法 - 設定インターフェイスで「表示」オプションを見つけて入力します。 - 「フォント サイズ」オプションを見つけて、サードパーティでフォント サイズを調整します。アプリケーション - フォント サイズの調整をサポートするアプリケーションをダウンロードしてインストールします - アプリケーションを開いて、関連する設定インターフェイスに入ります - 個人に応じて

Tomcatのポート番号を確認する方法 Tomcatのポート番号を確認する方法 Apr 21, 2024 am 08:00 AM

Tomcat のポート番号は、server.xml ファイルの <Connector> 要素の port 属性を確認することで確認できます。 Tomcat 管理インターフェイス (http://localhost:8080/manager/html) にアクセスし、[ステータス] タブを表示します。コマンドラインから「catalina.sh version」を実行し、「Port:」行を確認します。

モバイルドラゴンの卵を孵化させる秘密が明らかに(モバイルドラゴンの卵をうまく孵化させる方法を段階的に教えます) モバイルドラゴンの卵を孵化させる秘密が明らかに(モバイルドラゴンの卵をうまく孵化させる方法を段階的に教えます) May 04, 2024 pm 06:01 PM

テクノロジーの発展に伴い、モバイルゲームは人々の生活に欠かせないものになりました。かわいいドラゴンエッグの画像と面白い孵化過程で多くのプレイヤーの注目を集めており、その中でも注目を集めているゲームの一つがモバイル版ドラゴンエッグです。プレイヤーがゲーム内で自分のドラゴンをより適切に育成し成長させることができるように、この記事ではモバイル版でドラゴンの卵を孵化させる方法を紹介します。 1. 適切な種類のドラゴン エッグを選択する プレイヤーは、ゲーム内で提供されるさまざまな種類のドラゴン エッグの属性と能力に基づいて、自分に適したドラゴン エッグの種類を慎重に選択する必要があります。 2. 孵化機のレベルをアップグレードします。プレイヤーはタスクを完了し、小道具を収集することで孵化機のレベルを向上させる必要があります。孵化機のレベルは孵化速度と孵化成功率を決定します。 3. プレイヤーはゲームに参加する必要がある孵化に必要なリソースを収集します。

Tomcat で異なるポート番号を持つ 2 つのプロジェクトを実行する方法 Tomcat で異なるポート番号を持つ 2 つのプロジェクトを実行する方法 Apr 21, 2024 am 09:00 AM

Tomcat サーバー上で異なるポート番号を使用してプロジェクトを実行するには、次の手順が必要です。server.xml ファイルを変更し、Connector 要素を追加してポート番号を定義します。 Context 要素を追加して、ポート番号に関連付けられたアプリケーションを定義します。 WAR ファイルを作成し、対応するディレクトリ (webapps または webapps/ROOT) にデプロイします。 Tomcat を再起動して変更を適用します。

See all articles