??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲国产成人精品激情,亚洲一区日韩高清中文字幕亚洲 ,亚洲首页国产精品丝袜http://www.tkk7.com/songfei/articles/113536.html天外飞仙天外飞仙Wed, 25 Apr 2007 06:58:00 GMThttp://www.tkk7.com/songfei/articles/113536.htmlhttp://www.tkk7.com/songfei/comments/113536.htmlhttp://www.tkk7.com/songfei/articles/113536.html#Feedback0http://www.tkk7.com/songfei/comments/commentRss/113536.htmlhttp://www.tkk7.com/songfei/services/trackbacks/113536.html
 
配置WebLogic Server集群
下面为网上文?现ȝ一下自己配|时遇到的一些问题的解决Ҏ:

1.集群的概忉|q样?先徏立管理服务器,跟据下面的图可以徏h.q个不难,接下来就是徏立受理服务器,受理服务器可以徏立一到多?也可以跟据下面的囑־立v?不管是远E的q是本地的都可以v?接下来就是启动管理服务器?q个不难,再就是启动代理服务器?q个比较隄?在启动代理服务器以前先讲二点,一是理服务器启动以后不能部|应用程?我是q么理解?不确?要想部v应用׃定得Z个代理服务器,不管是在一台机子上q是在多台电脑上,都行.二启动了理服务器就可以q入控制?在控制台上可以新建受理服务器,如果要在理服务器上建受理服务器可以直接部|应用了.如果是别的计机上面则还没试,`接下来就是代理服务器的启?启动的domain文g我是从服务器上拷贝过?启动是在q行打上CMD也就是在dos控制C输入.D:\bea\user_projects\domains\base_domain\bin>下启动startManagedWebLogic.cmd文g,后面带上 你在理服务器上看到的代理的名称默认情况下ؓserver-0,接着再打?a >http://192.168.0.131:7001可以看到启动了.
Q本文讲q如何在WebLogic Server 8.1上配|集,以及通过Proxy Server来访问集)
 
预备知识
什么是Domain和Server
Domain
Domain是WebLogic Server实例的基本管理单元。所谓Domain是Q由配置为Administrator Server的WebLogic Server实例理的逻辑单元Q这个单元是有所有相兌源的集合?/div>
Server
Server是一个相对独立的Qؓ实现某些特定功能而结合在一L单元?/div>
Domain and Server的关p?/font>
一个Domain 可以包含一个或多个WebLogic Server实例Q甚xServer集群。一个Domain中有一个且只能有一个Server 担Q理Server的功能,其它的Server具体实现一个特定的逻辑功能?/div>
本文环境
Ø         q_QWindows 2000
Ø         软gQBea WebLogic Server 8.1 SP2
配置WebLogic Server集群
WebLogic集群的体pȝ?/font>
单层混合型的集群架构QClusterQ?/font>
q种架构所有的Web应用以及相关的服务应用全部置于集中的单一WLS实例中,q种架构的优势在于:
Ø         易于理
Ø         灉|的负载^衡机?/div>
Ø         更强的安全控?/div>
多层l构的集架构(ClusterQ?/font>
q种架构使用两个WLS集群Q一个放|表静态内容和集群ServletQ另一个放|集EJB。一般应用于下面q些情况Q?/div>
Ø         在负载^衡机刉要调用集EJB中的ҎӞ
Ø         在提供内容与提供对象的服务之间需要更大的机动性时Q?/div>
Ø         在需要更高的pȝE_性时Q?/div>
配置集群应用的必要条?/font>
Ø         集群中的所有Server必须位于同一|段Qƈ且必LIPq播(UDP)可到辄
Ø         集群中的所有Server必须使用相同的版?包括Service Pack
Ø         集群中的Server必须使用怹的静态IP地址。动态IP地址分配不能用于集群环境。如果服务器位于防火墙后面,而客h位于防火墙外面,那么服务器必L公共的静态IP地址Q只有这P客户端才能访问服务器
Ø         要以CLUSTER方式q行Q必L包含CLUSTER许可的LICENSE才行Q从Bea|站上下载的试用版本可以进行Cluster配置Q?/div>
配置前的准备工作
在配|集应用前要对集群的配|信息有一个良好的设计Q下面就是我们这ơ配|的集群信息Q?/div>
在同一台机器上配置集群
机器cd
操作pȝ
g配置
角色
备注
DELL PC
Win2000 Professional
IP:10.16.92.33PORT:7080
Administrator Server
 
DELL PC
Win2000 Professional
IP:10.16.92.33PORT:8080
Proxy Server
 
DELL PC
Win2000 Professional
IP:10.16.92.33PORT:7082
Managed Server
 
DELL PC
Win2000 Professional
IP:10.16.92.33PORT:7084
Managed Server
 
DELL PC
Win2000 Professional
IP:10.16.92.33PORT:7086
Managed Server
 
在同一|段内的不同机器上配|集?/div>
机器cd
操作pȝ
g配置
角色
备注
DELL PC
Win2000 Server
IP:10.16.92.7PORT:7080
Administrator Server
 
DELL PC
Win2000 Server
IP:10.16.92.7PORT:8080
Proxy Server
 
DELL PC
Win2000 Server
IP:10.16.92.7PORT:7082
Managed Server
 
DELL PC
Win2000 Server
IP:10.16.92.33PORT:7084
Managed Server
 
使用Domain Configuration Wizardq行配置
创徏新的Domain
       选择“Create a new WebLogic configuration”Q单?#8220;Next”按钮
选择安装cd
       选择安装“Basic WebLogic Server Domain”Q单?#8220;Next”按钮
选择定制安装
       选择“Custom”安装Q单?#8220;Next”按钮
输入Administrator Server的信?/font>
       输入Administrator Server的名Uͼ监听地址Q监听端口,如果需要SSL支持的话可以?#8220;SSL enabled”后面的复选取框上打勾Q配|SSL监听端口Q单?#8220;Next”按钮
 
是否配置Server、Cluster、Machine信息
       选择“Yes”Q对Server、Cluster、Machine信息q行配置Q,单击“Next”按钮
配置Managed Server信息
       输入Managed Server的名Uͼ监听地址Q监听端口,如果需要SSL支持的话Q可以在“SSL enabled”复选框上打勾,配置SSL监听端口。可以配|多个Managed Server。单?#8220;Next”按钮
配置Cluster信息
       输入Cluster的名UͼCluster的组播地址和端口,Cluster地址可输可不输。单?#8220;Next”按钮
Managed Serverd到Cluster?/font>
       选择左面列表中的Managed ServerQ将其添加到右面的列表中Q单?#8220;Next”按钮
配置Machine信息
       在此不对Machineq行配置Q单?#8220;Next”按钮
是否配置JDBC信息
       在此不对JDBC数据源和q接池进行配|,单击“Next”按钮
配置JMS信息
       在此不对JMSq行配置Q单?#8220;Next”按钮
配置~省pȝ理员用户名和密?/font>
       输入pȝ理员用户名和密码,q可以配|其它的pȝ理用户Q在此不做配|,单击“Next”按钮
配置Windows附加选项
       可以选择是否创徏开始菜单中的快h式,是否该服务作ؓWindowspȝ服务Q在q里我们全部选择“No”Q单?#8220;Next”按钮
配置服务的启动模式ƈ选择Java SDK
       选择“Development Mode”模式Qƈ选择标准的Java SDK 1.4Q在开发模式下会有比较丰富的调试信息,Ҏ们很有帮助,单击“Next”按钮
配置信息认以及选择安装路径
       pȝ列出您的配置信息Qƈ指定了缺省的安装路径QD:\bea\user_projects\domains\mydomainQ,在此我们安装\径定位在D:\bea\user_projects\clusterdomainQ单?#8220;Create”按钮
pȝ创徏Domain
       pȝҎ配置信息Q完成缺省的目录及文件的创徏
启动WebLogic服务
Ø         启动Administrator Server
使用startWebLogic命o启动Administrator Server
Ø         启动Managed Server
使用startManagedWeblogic命o启动Managed ServerQ它的命令格式是Q?/div>
startManagedWeblogic.cmd Managed Server的名U?/span> Administrator Server地址
同理可以启动nodeB和nodeCQ以及Proxy Server
通过HttpClusterServlet实现h的自动分发处?/font>
       HttpClusterServlet通过一个WebLogic服务器代理对WebLogic集群中的其他服务器成员的HTTPhQ?同时HttpClusterServletqؓ代理的HTTPh提供负蝲q与容错处理?/div>
       实际上实现是很简单的Q遵循下面几个步骤就可以L实现h的自动分发功能:
Ø         创徏一个代理ServerQ在此我们称qproxyServerQ?/div>
Ø         生成配置文gweb.xml
Ø         生成配置文gweblogic.xml
Ø         打包生成Web应用
Ø         在proxyServer上部|应用,q将该应用作为缺省的Web应用
创徏代理Server
       启动Administrator ServerQ然后进入Console控制収ͼhttp://10.16.92.33:7080/console/Q,在此我们代理Server与Administrator Server|于同一CZ上?/div>
       q入console控制台后Q在“Server”l点上单d键,在弹单上选择“Configure a New Server”Q然后配|代理Server的相关信息。(在这里只要指定名Uͼ监听地址Q监听端口就可以了)
 
HttpClusterServlet 的部|Ԍ主要是Servlet的声明和映射Qƈ讄初始化参敎ͼ可以创徏一个Web AppQ然后直接在web.xml中添加或在管理控制台上设|HttpClusterServlet的部|信息。最后将它发布给用来做代理的 ServerQƈ这个Web App讄个Server的缺省WEB应用?/div>
web.xml文gCZ
weblogic.xml文gCZ
打包WEB应用
       可以使用jar命oproxy应用打包成war文gQ我们徏一个时目录tempQ然后在其中建立如下目录l构Q?/div>
       使用如下的命令操作,可完成web应用的打包操作:
JAR –参数 WEB应用名称要打包的目录
       当然我们也可以直接部|该目录Q而无需打包Q这在项目的开发阶D|很有帮助的,便于修改?/div>
部vproxy应用
       启动Administrator ServerQ然后进入Console控制収ͼhttp://10.16.92.33:7080/console/Q,在此我们代理Server与Administrator Server|于同一CZ上?/div>
       q入console控制台后Q在“Web Application Modules” l点上单d键,在弹单上选择“Deploy a new Web Application Module”Q然后选择要部|的文g或目录,单击“Target Module”按钮Q然后选择“proxyServer”Q单?#8220;Continue”按钮Q到了下一步,单击“Deploy”按钮Q完成部|工作?/div>
       部v完成后,查看WEB应用的状态是“FAILS”Q造成q种情况的原因是“proxyServer”q没有启动,我们可以通过下面的命令启?#8220;proxyServer”Q?/div>
       然后点击“ReDeploy”Q重新部|应用,状态值将变ؓ“Success”?/div>
       WEB应用配置成缺省的WEB应用Qweblogic8.1与weblogic6.1有很大的不同Q?.1不再支持从console控制台完成配|的工作Q而是在weblogic.xml中通过下面的结点,完成配置的工作?/div>
       <context-root> / </context-root>
试proxy应用
       修改web.xml文gQ加入下面的l点Q然后重启服务?/div>
              <init-param>
                     <param-name>DebugConfigInfo</param-name>
                     <param-value>ON</param-value>
              </init-param>
打开览器,讉K下面的地址Q会得到下图所C的l果Q这p明你的配|是成功的?/div>
http://myserver:port/placeholder.jsp? __WebLogicBridgeConfig
myserver为服务地址Q在q里?0.16.92.7Q?/div>
port为proxy服务的端口(在这里是8080Q?/div>
placeholder.jspQ这是一个不存在的JSP文gQ您也可以随意指定文件名Q?/div>
__WebLogicBridgeConfigQ这个可千万不能写错呦!Q?/div>
试集群的分发功?/font>
~写试WEB应用q|?/font>
       我们来编写一个简单的WEB应用Q它会在控制台和览器上同时打印?#8220;OK”字样Q然后将q个WEB应用部v到集中所有Managed Server上面。(代码见附Ӟ
       在这里我们将通过Apache中所带的ab包来q行q发讉K的模拟测试,使用如下的命令就可以完成压力试?/div>
       ab –n 100 –c 10 http://10.16.92.7:8080/index.jsp
       ab是测试程序的名称
       参数n代表h的L?/div>
       参数c代表q发的请求数
       url试压力的页?/div>
注:使用q个命oӞ一定要在系l\径中能够扑ֈ该程序,否则不能执行?/div>
       压力试完成后,我们从Managed Server的控制台上可以看刎ͼnodeAQnodeBQnodeC都打印出?#8220;OK”字样Q这说明Q在q发h的情况下Q集能够将hq行分发Q以辑ֈ负蝲q的目的?/div>
       试应用的目录结构如下,部v与proxy应用的部|一P要注意的是要它部v在Managed Server上面?/div>
同一|段内不同机器部|集?/font>
       在不同机器上部v集群与上面的操作有一些不同,是在部|?#8220;Managed Server”Ӟ要注意的是,参见下面的图解?/div>
       在另外一台机器上配置“Managed Server”Ӟ要指?#8220;Admin Server”的名Uͼ监听地址Q监听端口?/div>
       另外要注意的是,“Managed Server”上的配置信息要与“Admin Server”中Cluster所指定的配|信息一致?/div>
       启动“Managed Server”的命令与上面的一P如下所C:
集群配置中要注意的问?/font>
Ø         Admin Server只用于集的理Q而不能参与集事务?/div>
Ø         Web应用应该部v到集上Q文件的同步是由WebLogic来完成的?/div>


天外飞仙 2007-04-25 14:58 发表评论
]]>TOMCAT源码分析(启动框架)http://www.tkk7.com/songfei/articles/105247.html天外飞仙天外飞仙Wed, 21 Mar 2007 05:07:00 GMThttp://www.tkk7.com/songfei/articles/105247.htmlhttp://www.tkk7.com/songfei/comments/105247.htmlhttp://www.tkk7.com/songfei/articles/105247.html#Feedback0http://www.tkk7.com/songfei/comments/commentRss/105247.htmlhttp://www.tkk7.com/songfei/services/trackbacks/105247.html

TOMCAT源码分析(启动框架)
前言Q?br />   本文是我阅读了TOMCAT源码后的一些心得。 主要是讲解TOMCAT的系l框Ӟ 以及启动程。若有错漏之处,敬请批评指教Q?br />Q?br />   毕竟TOMCAT的框架还是比较复杂的Q 单是从文字上理解, 是不那么Ҏ掌握TOMCAT的框架的。 所以得实践、实c再实践。 徏议下载一份TOMCAT的源码, 调试通过Q 然后单步跟t其启动q程。 如果有不明白的地方Q 再来查阅本文, 看是否能得到帮助。 我怿q样效果以及学习速度都会好很多!
   
1. Tomcat的整体框架结?br />   Tomcat的基本框Ӟ 分ؓ4个层ơ?br />   Top Level Elements:
    Server
    Service   
   Connector
    HTTP
    AJP
   Container
   Engine
     Host
   Context
   Component  
    manager
   logger
   loader
   pipeline
   valve
         ...
   站在框架的顶层的是Server和Service
   Server:  其实是BackGroudE序Q 在Tomcat里面的Server的用处是启动和监听服务端事gQ诸如重启、关闭等命o。?在tomcat的标准配|文Ӟserver.xml里面Q 我们可以看到?lt;Server port="8005" shutdown= "SHUTDOWN" debug="0">”这里的"SHUTDOWN"是server在监听服务端事g的时候所使用的命令字Q?br />   ServiceQ 在tomcat里面Q service是指一c问题的解决Ҏ。  通常我们会默认用tomcat提供的:Tomcat- Standalone 模式的service。 在q种方式下的service既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务?br />   
   Connector: Tomcat都是在容器里面处理问题的Q 而容器又到哪里去取得输入信息呢?
Connector是专干q个的。 他会把从socket传递过来的数据Q 封装成Request, 传递给容器来处理?br />   通常我们会用CUConnector,一U叫http connectoerQ 用来传递http需求的。 另一U叫AJPQ 在我们整合 apache与tomcat工作的时候, apache与tomcat之间是通过q个协议来互动的。 (说到apache与tomcat的整合工作,  通常我们的目的是Z让apache 获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)
   Container: 当http connector把需求传递给的container: Engin的时候, 我们的视U就应该Ud到Containerq个层面来了?br />   在Containerq个层, 我们包含?U容器: Engin, Host, Context.
   Engin: 收到service传递过来的需求, 处理后, 结果返回给service( service 是通过 connector q个媒介来和Engin互动的?.
   Host: Engin收到service传递过来的需求后Q不会自己处理, 而是交给合适的Host来处理?br />Host在这里就是虚拟主机的意思, 通常我们都只会用一个主机,既“localhost”本地机来处理。?br />   Context: Host接到了从Host传过来的需求后Q 也不会自己处理Q 而是交给合适的Context来处理。?br />   比如Q?lt;http://127.0.0.1:8080/foo/index.jsp>
         <http://127.0.1:8080/bar/index.jsp>
   前者交lfooq个Context来处理, 后者交lbarq个Context来处理?br />   很明昑֐Q context的意思其实就是一个web app的意思?br />   我们通常都会在server.xml里面做这L配置
   <Context path="/foo" docBase="D:/project/foo/web" />
   q个context容器Q就是用来干我们该干的事儿的地方的?br />   
   Compenent: 接下来, 我们l箋讲讲component是干什么用的?br />   我们得先理解一下容器和lg的关pR?br />   需求被传递到了容器里面, 在合适的时候, 会传递给下一个容器处理?br />   而容器里面又盛装着各种各样的组Ӟ 我们可以理解为提供各U各L增值服务?br />   manager: 当一个容器里面装了managerlg后,q个容器支持session理了, 事实上在tomcat里面的session理Q 就是靠的在context里面装的manager component.
   logger: 当一个容器里面装了loggerlg后, q个容器里所发生的事情, p该组件记录下来啦Q 我们通常会在logs/ q个目录下看见 catalina_log.time.txt 以及 localhost.time.txt ?localhost_examples_log.time.txt。 这是因ؓ我们分别为:engin, host以及context (examples)q三个容器安装了loggerlgQ 这也是默认安装Q 又叫做标配 Q)
   loader: loaderq个lg通常只会l我们的context容器使用Q loader是用来启动context以及理q个context的classloader用的?br />    pipline: pipeline是这样一个东西, 当一个容器决定了要把从上U传递过来的需求交l子容器的时候, 他就把这个需求放q容器的道(pipeline)里面厅R 而需求傻呼呼得在道里面动的时候, ׃被管道里面的各个阀门拦截下来。 比如管道里面放了两个阀门。 第一个阀门叫做“access_allow_vavle”, 也就是说需求流q来的时候,它会看这个需求是哪个IPq来的, 如果q个IP已经在黑名单里面了,  sure, 杀Q 第二个阀门叫做“defaul_access_valve”它会做例行的检查, 如果通过的话QOKQ 把需求传递给当前容器的子容器。 就是通过q种方式Q 需求就在各个容器里面传递,动Q 最后抵辄的地的了?br />    valve: 是上面所说的阀门啦?br />   Tomcat里面大概是q么些东西, 我们可以单地q么理解tomcat的框Ӟ它是一U自上而下Q 容器里又包含子容器的这样一U结构?br />2. Tomcat的启动流E?br />   q篇文章是讲tomcat怎么启动的,既然我们大体上了解了TOMCAT的框架结构了Q 那么我们可以望文生意地q到tomcat的启动, 会先启动父容器,然后逐个启动里面的子容器。 启动每一个容器的时候, 都会启动安插在他w上的组件。 当所有的lg启动完毕Q 所有的容器启动完毕的时候,  tomcat本n也就启动完毕了?br />   理成章圎ͼ 我们同样可以猜到Q tomcat的启动会分成两大部分Q 第一步是装配工作。 第二步是启动工作。?br />   装配工作是为父容器装上子容器, 为各个容器安插进lg的工作。 这个地Ҏ们会用到digester模式Q 至于digester模式什么, 有什么用Q 怎么工作? 请参考?lt;http://software.ccidnet.com/pub/article/c322_a31671_p2.html>
   启动工作是在装配工作之后Q 一旦装配成功了Q 我们就只需要点燃最上面的一根导U, 整个tomcat׃被激zv来。 这好比我们要开一辆已l装配好了的汽R的时候一P我们只要把钥匙插q钥匙孔Q一拧,汽R的引擎就会发动v来,I׃开hQ 安全装|就会生效, 如此一来,汽R整个发动v来了。(q个q程实和TOMCAT的启动过E不谋而和Q 让我们不得不怀疑 TOMCAT的设计者是在GE做JAVA开发的Q?br />2.1 一些有意思的名称Q?br />   Catalina
   Tomcat
   Bootstrap
   Engin
   Host
   Context
   他们的意思很有意思:
   Catalina: q程轰炸?br />   Tomcat: 熊猫轰炸机?- 轰炸机的一U(q让我想起了让国人引以ؓ豪的熊猫手机Q是不是英文可以叫做tomcat??? Q 又让我惌v了另一则广告: 波导-手机中的战斗机、L?客机中的战斗机 )
   Bootstap: 引导
   Engin: 发动?br />   Host: LQ领?br />   Context: 内容Q 目标, 上下?br />   
   ... 在许多许多年后, C人类已经灭绝。 后C生物发现了这些单词零落零落在一块。 一个自以ؓ聪明的家伙把q些东西译出来了: 
   在地勤h员的引导(bootstrap)下, 一架蘪炸架(catalina)腄跃vQ 远看是熊猫轰炸?tomcat)Q 近看还是熊猫蘪炸机Q 凭借着优秀的发动机技?engin)Q 这架熊猫蘪炸机飞了敌国的领土上空(host)Q 对准目?context)投下了毁天灭地的核弹_波~ C生物p么隔屁了~
 
   lg所qͼ q又不得不让惛_GE是不是也参与了军事设备的生呢?
   反对帝国主义! 反对霸权主义! 和^万岁Q 自׃岁!
   
2.2  历史是那么惊h的相| tomcat的启动就是从org.apache.catalina.startup.Bootstrapq个cL然启动的Q?br />   在Bootstrap里做了两件事Q?br />   1. 指定?U类型classloader:
      commonLoader: common/classes、common/lib、common/endorsed
      catalinaLoader: server/classes、server/lib、commonLoader
      sharedLoaderQ  shared/classes、shared/lib、commonLoader
   2. 引导Catalina的启动?br />      用Reflection技术调用org.apache.catalina.startup.Catalina的processҎQ ƈ传递参数过厅R?br />   
2.3 Catalina.java
   Catalina完成了几个重要的dQ?br />   1. 使用Digester技术装配tomcat各个容器与组件?br />      1.1 装配工作的主要内Ҏ安装各个大g。 比如server下有什么样的servcie。 Host会容U_个context。 Context都会使用到哪些组件等{。?br />      1.2 同时呢, 在装配工作这一步, q完成了mbeans的配|工作。 在q里Q我单地但不十分_地描qC下mbean是什么,q什么用的?br />          我们自己生成的对象, 自己理Q 天l地义! 但是如果我们创徏了对象了Q 想让别人来, 怎么办呢Q 我惌得告诉别h我们都有什么, 以及通过什么方法可以找刊W 吧Q JMX技术给我们提供了一U手Dc JMX里面主要?U东ѝMbean, agent,  connector.
       MbeanQ 用来映我们的对象。也许mbean是我们创徏的对象, 也许不是Q 但有了它, 可以引用到我们的对象了?br />       Agent:  通过它, 可以找到mbean了?br />       Connector: q接Agent的方式。 可以是http的, 也可以是rmi的,q可以直接通过socket?br />      发生在tomcat 装配q程中的事情:  GlobalResourcesLifecycleListener cȝ初始化会被触发:
         protected static Registry registry = MBeanUtils.createRegistry();  会运?br />         MBeanUtils.createRegistry()  会依?/org/apache/catalina/mbeans/mbeans-descriptors.xmlq个配置文g创徏 mbeans. Ok, 外界有了条途径讉Ktomcat中的各个lg了。(有点像后门儿Q?br />   2. 为top level 的server 做初始化工作。 实际上是做通常会配|给service的两条connector.(http, ajp)
   3. 从serverq个容器开始启动, 点燃整个tomcat.
   4. 为server做一个hookE序Q 检当server shutdown的时候, 关闭tomcat的各个容器用?br />   5. 监听8005端口Q 如果发?SHUTDOWN"Q默认培植下字符Ԍq来Q 关?005serverSocket?br />2.4 启动各个容器
   1. Server
      触发Server容器启动?before_start)Q 启动中(start)Q 启动后(after_start)3个事Ӟ q运行相应的事g处理器?br />      启动Server的子容器QServcie. 
   2. Service
      启动Service的子容器QEngin
      启动Connector
   3. Engin
      CEnginq个层次Q以及以下别的容器Q Tomcat׃用了比较一致的启动方式了?br />      首先Q  运行各个容器自q有一些Q?br />      随后Q  触发启动前事g
      立即Q  设|标{,pC容器已经启动
      接着Q  启动容器中的各个组Ӟ loader, logger, manager{等
      再接着Q启动mappinglg。(?Q?br />      紧跟着Q启动子容器?br />      接下来,启动该容器的道(pipline)
      然后Q  触发启动中事g
      最后,  触发启动后事件?br /> 
      Engin大致会这么做Q Host大致也会q么做, Context大致q是会这么做。 那么很昄圎ͼ 我们需要在q里使用C码复用的技术。 tomcat在处理这个问题的时候, 漂亮C用了抽象cL处理。 ContainerBase. 最后得这部分完成复杂功能的代码显得干净利落Q 干l爽快, 实在是o得叹止, l细品来Q 直觉如享佳珍, 另h齉K留香Q 留恋往q啊Q?br />      
      Engin的触发启动前事g里, 会激zȝ定在Engin上的唯一一个ListenerQEnginConfig?br />      q个EnginConfigcd本上没有做什么事情, 是把EnginConfig的调试别设|ؓ和Engin相当。 另外就是输出几行文本, 表示Engin已经配置完毕Q ƈ没有做什么实质性的工作?br />      ?: mappinglg的用处是Q 当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢Q 这个由mapping lg来定夺?br />    
   4. Host
       同Engin一P 也是调用ContainerBase里面的start()ҎQ 不q之前做了些自个儿的d,是往Hostq个容器的通道QpiplineQ里面, 安装了一个叫?br /> “org.apache.catalina.valves.ErrorReportValve”的阀门?br />       q个阀门的用处是这LQ  需求在被Engin传递给Host后, 会l传递给Context做具体的处理。 这里需求其实就是作为参C递的Request, Response。 所以在context把需求处理完后, 通常会改动response。 而这?org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误Q 如果有做相应的处理?br />   5. Context
       Cq里Q 就l于轮到了tomcat启动中真正的重头戏,启动Context了?br /> StandardContext.start() q个启动Context容器的方法被StandardHost调用.
 5.1 webappResources 该context所指向的具体目?br /> 5.2 安装defaultContex, DefaultContext 是默认Context。 如果我们在一个Host下面安装?DefaultContextQ而且defaultContext里面又安装了一个数据库q接池资源的话。 那么其他所有的在该Host下的 Context, 都可以直接用这个数据库q接池, 而不用格外做配置了?br />  5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoaderq个cR   Loader是用来指定q个context会用到哪些类啊, 哪些jar包啊q些什么的?br /> 5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager 。 Manager是用来管理session的?br />     其实session的管理也很好实现。 以一U简单的session理Z。 当需求传递过来的时候, 在Request对象里面有一?sessionId 属性。 OKQ 得到这个sessionId后, 我们可以把它作为map的keyQ而value我们可以攄一?HashMap. HashMap里边儿, 再放我们x的东ѝ?br /> 5.5 postWorkDirectory (). Tomcat下面有一个work目录。 我们把临时文g都扔在那儿去。 这个步骤就是在那里创徏一个目录。 一般说来会?CATALINA_HOME%/work/Standalone\localhost\ q个地方生成一个目录?br />5.6  Binding thread。到了这里, 应该发生 class Loader 互换了。 之前是看得见tomcat下面所有的class 和lib. 接下来需要看得见当前context下的class。 所以要讄contextClassLoader, 同时q要把旧?ClassLoader记录下来Q因Z后还要用的?br />5.7  启动 Loader. 指定q个Context具体要用哪些classesQ 用到哪些jar文g。 如果reloadable讄成了true, ׃启动一个线E来监视classes的变化, 如果有变化就重新启动Context?br />5.8  启动logger
5.9  触发安装在它w上的一个监听器?br /> lifecycle.fireLifecycleEvent(START_EVENT, null); 
 作ؓ监听器之一QContextConfig会被启动. ContextConfig是用来配置web.xml的。 比如这个Context有多ServletQ 又有多FilterQ 就是在q里lContext装上ȝ?br /> 5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml q个文g?br /> 5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文g
5.9.3 validateSecurityRoles 权限验证。 通常我们在访?admin 或?manager的时候,需要用戯么是 admin的要么是manager的, 才能讉K。 而且我们q可以限刉些资源可以访问, 而哪些不能。 都是在q里实现的?br />5.9.4 tldScan: 扫描一下, 需要用到哪些标{?tag lab)
5.10 启动 manager
5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称Q?br />index.html、index.htm、index.jsp p默认地绑在了q个context?br /> 5.12 listenerStart 配置listener
 5.13 filterStart 配置 filter
 5.14 启动带有<load-on-startup>1</load-on-startup>的Servlet.
  序是从到大: 1,2,3… 最后是0
  默认情况下, 臛_会启动如?个的Servlet: 
  org.apache.catalina.servlets.DefaultServlet   
      处理静态资源的Servlet. 什么图片啊Q html啊, css啊, js啊都找他
  org.apache.catalina.servlets.InvokerServlet
      处理没有做Servlet Mapping的那些Servlet.
  org.apache.jasper.servlet.JspServlet 
      处理JSP文g?
       5.15  标识context已经启动完毕?br /> C多少个步骤啊Q Contextȝ是启动完毕喽?br />    OK! 走到了这里, 每个容器以及lg都启动完毕。 Tomcatl于不辞辛劳Cؓ人民服务了!
3. 参考文献:
    <http://jakarta.apache.org/tomcat/>
    <http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
    
4. 后记
    q篇文章是讲解tomcat启动框架的,q有文章是讲解TOMCAT里面的消息处理流E的l节的。 文章内容已l写好了Q 现在正在整理阶Dc 相信很快就可以做出来, 大家共同研究共同q步?br />    q篇文章是独自分析TOMCAT源码所写的Q 所以一定有地方是带有个Z观色彩, 隑օ会有片面之处。若有不当之处敬h评指教,q样不仅可以使刚开始研ITOMCAT的兄弟们走弯\Q 我也可以学Cѝ?br />    email: sojan_java@yahoo.com.cn

5. tomcat源码分析(消息处理)



天外飞仙 2007-03-21 13:07 发表评论
]]>调用tomcat自带的连接池所要书写的代码和配|?/title><link>http://www.tkk7.com/songfei/articles/105201.html</link><dc:creator>天外飞仙</dc:creator><author>天外飞仙</author><pubDate>Wed, 21 Mar 2007 02:54:00 GMT</pubDate><guid>http://www.tkk7.com/songfei/articles/105201.html</guid><wfw:comment>http://www.tkk7.com/songfei/comments/105201.html</wfw:comment><comments>http://www.tkk7.com/songfei/articles/105201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/songfei/comments/commentRss/105201.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/songfei/services/trackbacks/105201.html</trackback:ping><description><![CDATA[tomcat里的D:\tomcat5.5.15\conf\Catalina\localhost文g夹下.写上q样的xml文g,内容如下.<br /><?xml version="1.0" encoding="UTF-8"?><br /><Context<br /> docBase="工程路径\WebRoot"<br /> path="jxhealth"<br /> reloadable="true"><br /> <Resource<br />  name="jdbc/oracle"<br />  auth="Container"<br />  type="javax.sql.DataSource"<br />  maxActive="20"<br />  maxIdle="10"<br />  maxWait="5000"<br />  username="test"<br />  password="test"<br />  driverClassName="oracle.jdbc.driver.OracleDriver"<br />  url="jdbc:oracle:thin:@192.168.0.80:1521:JXSMJK" /><br /></Context><br /><br />web.xml加上q样一句话.<br /><!-- 需要引用的JNDI资源 --><br /> <resource-ref><br />  <res-ref-name>jdbc/oracle</res-ref-name><br />  <res-type>javax.sql.DataSource</res-type><br />  <res-auth>Container</res-auth><br /> </resource-ref><br />java文g里这样写<br />public class DBConnection {<br /> private static String JNDI_NAME="jdbc/plantDB";<br /> <br /> public DBConnection(){ <br /> }<br /> <br /> public Connection getConnection(){ <br />  Connection cn=null; <br />  try{<br />   InitialContext initTxt=new InitialContext();<br />   //Context cTxt=(Context)initTxt.lookup("java:comp/env");<br />   //Object obj=(Object)cTxt.lookup(JNDI_NAME);<br />   //DataSource ds=(DataSource)obj;   <br />   DataSource ds=(DataSource)initTxt.lookup("java:comp/env/"+JNDI_NAME);<br />   cn=ds.getConnection();<br />   //cn.setAutoCommit(true);   <br />  }catch(Exception E){<br />   String strMsg=E.getMessage().toString();<br />   System.out.print(strMsg);<br />  }  <br />  return cn;<br /> }<br /> <br />}<img src ="http://www.tkk7.com/songfei/aggbug/105201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/songfei/" target="_blank">天外飞仙</a> 2007-03-21 10:54 <a href="http://www.tkk7.com/songfei/articles/105201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>q接?/title><link>http://www.tkk7.com/songfei/articles/62323.html</link><dc:creator>天外飞仙</dc:creator><author>天外飞仙</author><pubDate>Tue, 08 Aug 2006 03:31:00 GMT</pubDate><guid>http://www.tkk7.com/songfei/articles/62323.html</guid><wfw:comment>http://www.tkk7.com/songfei/comments/62323.html</wfw:comment><comments>http://www.tkk7.com/songfei/articles/62323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/songfei/comments/commentRss/62323.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/songfei/services/trackbacks/62323.html</trackback:ping><description><![CDATA[ <table class="showinfo" style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellspacing="0" cellpadding="3" width="100%" align="center" border="0"> <tbody> <tr> <td class="showTitle" align="middle">用连接池提高Servlet讉K数据库的效率</td> </tr> <tr> <td> <table cellspacing="0" cellpadding="0" align="left" border="0"> <tbody> <tr> <td> <script language="javascript" src="/ad/js/edu_left_300-300.js"> </script> </td> </tr> </tbody> </table>Java Servlet作ؓ首选的服务器端数据处理技术,正在q速取代CGI脚本。Servlet越CGI的优势之一在于Q不仅多个请?<br />可以׃n公用资源Q而且q可以在不同用户h之间保留持箋数据。本文介l一U充分发挥该特色的实用技术,x据库q?<br />接池?<br /><br /><br />一、实现连接池的意?<br /><br />动态Web站点往往用数据库存储的信息生成Web面Q每一个页面请求导致一ơ数据库讉K。连?<br />数据库不仅要开销一定的通讯和内存资源,q必d成用户验证、安全上下文配置q类dQ因而往往成ؓ最时的操 <br />作。当Ӟ实际的连接时间开销千变万化Q但1?Ugqƈ非不常见。如果某个基于数据库的Web应用只需建立一ơ初始连 <br />接,不同面h能够׃n同一q接Q就能获得显著的性能改善?<br />Servlet是一个JavacRServlet引擎Q它可能是Web服务软g的一部分Q也可能是一个独立的附加模块Q在pȝ启动或Servlet <br />W一ơ被h时将该类装入Java虚拟机ƈ创徏它的一个实例。不同用戯求由同一Servlet实例的多个独立线E处理。那些要 <br />求在不同h之间持箋有效的数据既可以用Servlet的实例变量来保存Q也可以保存在独立的辅助对象中?<br />用JDBC讉K数据库首先要创徏与数据库之间的连接,获得一个连接对象(ConnectionQ,p接对象提供执行SQL语句的方法?<br />本文介绍的数据库q接池包括一个管理类DBConnectionManagerQ负责提供与多个q接池对象(DBConnectionPoolc)之间 <br />的接口。每一个连接池对象理一lJDBCq接对象Q每一个连接对象可以被L数量的Servlet׃n?<br />cDBConnectionPool提供以下功能Q?<br /><br />1) 从连接池获取Q或创徏Q可用连接?<br />2) 把连接返回给q接池?<br />3) 在系l关闭时释放所有资源,关闭所有连接?<br /><br />此外Q?DBConnectionPoolc还能够处理无效q接Q原来登Cؓ可用的连接,׃某种原因不再可用Q如时Q通讯问题Q?<br />Qƈ能够限制q接池中的连接L不超q某个预定倹{?<br />理cDBConnectionManager用于理多个q接池对象,它提供以下功能: <br /><br />1) 装蝲和注册JDBC驱动E序?<br />2) Ҏ在属性文件中定义的属性创接池对象?<br />3) 实现q接池名字与其实例之间的映射?<br />4) 跟踪客户E序对连接池的引用,保证在最后一个客L序结束时安全地关闭所有连接池?<br /><br />本文余下部分详l说明这两个c,最后给Z个示例演CServlet使用q接池的一般过E?<br /><br /><br />二、具体实?<br /><br />DBConnectionManager.javaE序清单如下Q?<br /><br />001 import java.io.*; <br />002 import java.sql.*; <br />003 import java.util.*; <br />004 import java.util.Date; <br />005 <br />006 /** <br />007 * 理cDBConnectionManager支持对一个或多个由属性文件定义的数据库连?<br />008 * 池的讉K.客户E序可以调用getInstance()Ҏ讉K本类的唯一实例. <br />009 */ <br />010 public class DBConnectionManager { <br />011 static private DBConnectionManager instance; // 唯一实例 <br />012 static private int clients; <br />013 <br />014 private Vector drivers = new Vector(); <br />015 private PrintWriter log; <br />016 private Hashtable pools = new Hashtable(); <br />017 <br />018 /** <br />019 * q回唯一实例.如果是第一ơ调用此Ҏ,则创建实?<br />020 * <br />021 * @return DBConnectionManager 唯一实例 <br />022 */ <br />023 static synchronized public DBConnectionManager getInstance() { <br />024 if (instance == null) { <br />025 instance = new DBConnectionManager(); <br />026 } <br />027 clients++; <br />028 return instance; <br />029 } <br />030 <br />031 /** <br />032 * 建构函数U有以防止其它对象创建本cd?<br />033 */ <br />034 private DBConnectionManager() { <br />035 init(); <br />036 } <br />037 <br />038 /** <br />039 * 连接对象返回给由名字指定的q接?<br />040 * <br />041 * @param name 在属性文件中定义的连接池名字 <br />042 * @param con q接对象 <br />043 */ <br />044 public void freeConnection(String name, Connection con) { <br />045 DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br />046 if (pool != null) { <br />047 pool.freeConnection(con); <br />048 } <br />049 } <br />050 <br />051 /** <br />052 * 获得一个可用的(I闲?q接.如果没有可用q接,且已有连接数于最大连接数 <br />053 * 限制,则创建ƈq回新连?<br />054 * <br />055 * @param name 在属性文件中定义的连接池名字 <br />056 * @return Connection 可用q接或null <br />057 */ <br />058 public Connection getConnection(String name) { <br />059 DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br />060 if (pool != null) { <br />061 return pool.getConnection(); <br />062 } <br />063 return null; <br />064 } <br />065 <br />066 /** <br />067 * 获得一个可用连?若没有可用连?且已有连接数于最大连接数限制, <br />068 * 则创建ƈq回新连?否则,在指定的旉内等待其它线E释放连? <br />069 * <br />070 * @param name q接池名?<br />071 * @param time 以毫U计的等待时?<br />072 * @return Connection 可用q接或null <br />073 */ <br />074 public Connection getConnection(String name, long time) { <br />075 DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br />076 if (pool != null) { <br />077 return pool.getConnection(time); <br />078 } <br />079 return null; <br />080 } <br />081 <br />082 /** <br />083 * 关闭所有连?撤销驱动E序的注?<br />084 */ <br />085 public synchronized void release() { <br />086 // {待直到最后一个客L序调?<br />087 if (--clients != 0) { <br />088 return; <br />089 } <br />090 <br />091 Enumeration allPools = pools.elements(); <br />092 while (allPools.hasMoreElements()) { <br />093 DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); <br />094 pool.release(); <br />095 } <br />096 Enumeration allDrivers = drivers.elements(); <br />097 while (allDrivers.hasMoreElements()) { <br />098 Driver driver = (Driver) allDrivers.nextElement(); <br />099 try { <br />100 DriverManager.deregisterDriver(driver); <br />101 log("撤销JDBC驱动E序 " + driver.getClass().getName()+"的注?); <br />102 } <br />103 catch (SQLException e) { <br />104 log(e, "无法撤销下列JDBC驱动E序的注? " + driver.getClass().getName()); <br />105 } <br />106 } <br />107 } <br />108 <br />109 /** <br />110 * Ҏ指定属性创接池实例. <br />111 * <br />112 * @param props q接池属?<br />113 */ <br />114 private void createPools(Properties props) { <br />115 Enumeration propNames = props.propertyNames(); <br />116 while (propNames.hasMoreElements()) { <br />117 String name = (String) propNames.nextElement(); <br />118 if (name.endsWith(".url")) { <br />119 String poolName = name.substring(0, name.lastIndexOf(".")); <br />120 String url = props.getProperty(poolName + ".url"); <br />121 if (url == null) { <br />122 log("没有接池" + poolName + "指定URL"); <br />123 continue; <br />124 } <br />125 String user = props.getProperty(poolName + ".user"); <br />126 String password = props.getProperty(poolName + ".password"); <br />127 String maxconn = props.getProperty(poolName + ".maxconn", "0"); <br />128 int max; <br />129 try { <br />130 max = Integer.valueOf(maxconn).intValue(); <br />131 } <br />132 catch (NumberFormatException e) { <br />133 log("错误的最大连接数限制: " + maxconn + " .q接? " + poolName); <br />134 max = 0; <br />135 } <br />136 DBConnectionPool pool = <br />137 new DBConnectionPool(poolName, url, user, password, max); <br />138 pools.put(poolName, pool); <br />139 log("成功创徏q接? + poolName); <br />140 } <br />141 } <br />142 } <br />143 <br />144 /** <br />145 * d属性完成初始化 <br />146 */ <br />147 private void init() { <br />148 InputStream is = getClass().getResourceAsStream("/db.properties"); <br />149 Properties dbProps = new Properties(); <br />150 try { <br />151 dbProps.load(is); <br />152 } <br />153 catch (Exception e) { <br />154 System.err.println("不能d属性文? " + <br />155 "L保db.properties在CLASSPATH指定的\径中"); <br />156 return; <br />157 } <br />158 String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log"); <br />159 try { <br />160 log = new PrintWriter(new FileWriter(logFile, true), true); <br />161 } <br />162 catch (IOException e) { <br />163 System.err.println("无法打开日志文g: " + logFile); <br />164 log = new PrintWriter(System.err); <br />165 } <br />166 loadDrivers(dbProps); <br />167 createPools(dbProps); <br />168 } <br />169 <br />170 /** <br />171 * 装蝲和注册所有JDBC驱动E序 <br />172 * <br />173 * @param props 属?<br />174 */ <br />175 private void loadDrivers(Properties props) { <br />176 String driverClasses = props.getProperty("drivers"); <br />177 StringTokenizer st = new StringTokenizer(driverClasses); <br />178 while (st.hasMoreElements()) { <br />179 String driverClassName = st.nextToken().trim(); <br />180 try { <br />181 Driver driver = (Driver) <br />182 Class.forName(driverClassName).newInstance(); <br />183 DriverManager.registerDriver(driver); <br />184 drivers.addElement(driver); <br />185 log("成功注册JDBC驱动E序" + driverClassName); <br />186 } <br />187 catch (Exception e) { <br />188 log("无法注册JDBC驱动E序: " + <br />189 driverClassName + ", 错误: " + e); <br />190 } <br />191 } <br />192 } <br />193 <br />194 /** <br />195 * 文本信息写入日志文?<br />196 */ <br />197 private void log(String msg) { <br />198 log.println(new Date() + ": " + msg); <br />199 } <br />200 <br />201 /** <br />202 * 文本信息与异常写入日志文g <br />203 */ <br />204 private void log(Throwable e, String msg) { <br />205 log.println(new Date() + ": " + msg); <br />206 e.printStackTrace(log); <br />207 } <br />208 <br />209 /** <br />210 * 此内部类定义了一个连接池.它能够根据要求创建新q接,直到预定的最 <br />211 * 大连接数为止.在返回连接给客户E序之前,它能够验证连接的有效? <br />212 */ <br />213 class DBConnectionPool { <br />214 private int checkedOut; <br />215 private Vector freeConnections = new Vector(); <br />216 private int maxConn; <br />217 private String name; <br />218 private String password; <br />219 private String URL; <br />220 private String user; <br />221 <br />222 /** <br />223 * 创徏新的q接?<br />224 * <br />225 * @param name q接池名?<br />226 * @param URL 数据库的JDBC URL <br />227 * @param user 数据库帐??null <br />228 * @param password 密码,?null <br />229 * @param maxConn 此连接池允许建立的最大连接数 <br />230 */ <br />231 public DBConnectionPool(String name, String URL, String user, String password, <br />232 int maxConn) { <br />233 this.name = name; <br />234 this.URL = URL; <br />235 this.user = user; <br />236 this.password = password; <br />237 this.maxConn = maxConn; <br />238 } <br />239 <br />240 /** <br />241 * 不再用的q接q回l连接池 <br />242 * <br />243 * @param con 客户E序释放的连?<br />244 */ <br />245 public synchronized void freeConnection(Connection con) { <br />246 // 指定连接加入到向量末尾 <br />247 freeConnections.addElement(con); <br />248 checkedOut--; <br />249 notifyAll(); <br />250 } <br />251 <br />252 /** <br />253 * 从连接池获得一个可用连?如没有空闲的q接且当前连接数于最大连?<br />254 * 数限?则创建新q接.如原来登Cؓ可用的连接不再有?则从向量删除? <br />255 * 然后递归调用自己以尝试新的可用连? <br />256 */ <br />257 public synchronized Connection getConnection() { <br />258 Connection con = null; <br />259 if (freeConnections.size() > 0) { <br />260 // 获取向量中第一个可用连?<br />261 con = (Connection) freeConnections.firstElement(); <br />262 freeConnections.removeElementAt(0); <br />263 try { <br />264 if (con.isClosed()) { <br />265 log("从连接池" + name+"删除一个无效连?); <br />266 // 递归调用自己,试再次获取可用q接 <br />267 con = getConnection(); <br />268 } <br />269 } <br />270 catch (SQLException e) { <br />271 log("从连接池" + name+"删除一个无效连?); <br />272 // 递归调用自己,试再次获取可用q接 <br />273 con = getConnection(); <br />274 } <br />275 } <br />276 else if (maxConn == 0 || checkedOut < maxConn) { <br />277 con = newConnection(); <br />278 } <br />279 if (con != null) { <br />280 checkedOut++; <br />281 } <br />282 return con; <br />283 } <br />284 <br />285 /** <br />286 * 从连接池获取可用q接.可以指定客户E序能够{待的最长时?<br />287 * 参见前一个getConnection()Ҏ. <br />288 * <br />289 * @param timeout 以毫U计的等待时间限?<br />290 */ <br />291 public synchronized Connection getConnection(long timeout) { <br />292 long startTime = new Date().getTime(); <br />293 Connection con; <br />294 while ((con = getConnection()) == null) { <br />295 try { <br />296 wait(timeout); <br />297 } <br />298 catch (InterruptedException e) {} <br />299 if ((new Date().getTime() - startTime) >= timeout) { <br />300 // wait()q回的原因是时 <br />301 return null; <br />302 } <br />303 } <br />304 return con; <br />305 } <br />306 <br />307 /** <br />308 * 关闭所有连?<br />309 */ <br />310 public synchronized void release() { <br />311 Enumeration allConnections = freeConnections.elements(); <br />312 while (allConnections.hasMoreElements()) { <br />313 Connection con = (Connection) allConnections.nextElement(); <br />314 try { <br />315 con.close(); <br />316 log("关闭q接? + name+"中的一个连?); <br />317 } <br />318 catch (SQLException e) { <br />319 log(e, "无法关闭q接? + name+"中的q接"); <br />320 } <br />321 } <br />322 freeConnections.removeAllElements(); <br />323 } <br />324 <br />325 /** <br />326 * 创徏新的q接 <br />327 */ <br />328 private Connection newConnection() { <br />329 Connection con = null; <br />330 try { <br />331 if (user == null) { <br />332 con = DriverManager.getConnection(URL); <br />333 } <br />334 else { <br />335 con = DriverManager.getConnection(URL, user, password); <br />336 } <br />337 log("q接? + name+"创徏一个新的连?); <br />338 } <br />339 catch (SQLException e) { <br />340 log(e, "无法创徏下列URL的连? " + URL); <br />341 return null; <br />342 } <br />343 return con; <br />344 } <br />345 } <br />346 } <br /><br /><br /><br /><br />三、类DBConnectionPool说明 <br /><br />该类?09?45行实玎ͼ它表C指向某个数据库的连接池。数据库由JDBC URL标识。一个JDBC URL׃部分l成Q协议标?<br />QLjdbcQ,驱动E序标识Q如 odbc、idb、oracle{)Q数据库标识Q其格式依赖于驱动程序)。例如,jdbc:odbc:de <br />moQ即是一个指向demo数据库的JDBC URLQ而且讉K该数据库要用JDBC-ODBC驱动E序。每个连接池都有一个供客户E序 <br />使用的名字以及可选的用户帐号、密码、最大连接数限制。如果Web应用E序所支持的某些数据库操作可以被所有用h行, <br />而其它一些操作应q别许可的用户执行Q则可以ZcL作分别定义连接池Q两个连接池使用相同的JDBC URLQ但使用?<br />同的帐号和密码?<br />cDBConnectionPool的徏构函数需要上q所有数据作为其参数。如222?38行所C,q些数据被保存ؓ它的实例变量Q?<br />?52?83行?85?05行所C, 客户E序可以使用DBConnectionPoolcL供的两个Ҏ获取可用q接。两者的共同之处 <br />在于Q如q接池中存在可用q接Q则直接q回Q否则创建新的连接ƈq回。如果没有可用连接且已有q接L{于最大限?<br />敎ͼW一个方法将直接q回nullQ而第二个Ҏ等待直到有可用q接为止?<br />所有的可用q接对象均登记在名ؓfreeConnections的向量(VectorQ中。如果向量中有多于一个的q接QgetConnection() <br />L选取W一个。同Ӟ׃新的可用q接L从尾部加入向量,从而得数据库q接׃长时间闲|而被关闭的风险减?<br />到最程度?<br />W一个getConnection()在返回可用连接给客户E序之前Q调用了isClosed()Ҏ验证q接仍旧有效。如果该q接被关闭或 <br />触发异常QgetConnection()递归地调用自׃试获取另外的可用连接。如果在向量freeConnections中不存在M可用q?<br />接,getConnection()Ҏ查是否已l指定最大连接数限制。如已经指定Q则查当前连接数是否已经到达极限。此?<br />maxConn?表示没有限制。如果没有指定最大连接数限制或当前连接数于该|该方法尝试创建新的连接。如创徏成功Q?<br />则增加已使用q接的计数ƈq回Q否则返回空倹{?<br />?25?45行所C,创徏新连接由newConnection()Ҏ实现。创E与是否已经指定数据库帐受密码有兟?<br />JDBC的DriverManagercL供多个getConnection()ҎQ这些方法要用到JDBC URL与其它一些参敎ͼ如用户帐号和密码{?<br />DriverManager用指定的JDBC URL定适合于目标数据库的驱动程序及建立q接?<br />?85?05行实现的W二个getConnection()Ҏ需要一个以毫秒为单位的旉参数Q该参数表示客户E序能够{待的最?<br />旉。徏立连接的具体操作仍旧q一个getConnection()Ҏ实现?<br />该方法执行时先将startTime初始化ؓ当前旉。在while循环中尝试获得一个连接。如果失败,则以l定的时间gؓ参数?<br />用wait()。wait()的返回可能是׃其它U程调用notify()或notifyAll()Q也可能是由于预定时间已到。ؓ扑ևwait()q?<br />回的真正原因Q程序用当前旉减开始时_startTimeQ,如差值大于预定时间则q回I|否则再次调用getConnection()?<br />把空闲的q接登记到连接池?40?50行的freeConnection()Ҏ实现Q它的参Cؓq回l连接池的连接对象。该对象被加 <br />入到freeConnections向量的末,然后减少已用连接计数。调用notifyAll()是ؓ了通知其它正在{待可用q接的线E?<br />许多Servlet引擎为实现安全关闭提供多U方法。数据库q接池需要知道该事g以保证所有连接能够正常关闭。DBConnectionManager <br />c负协调整个关闭q程Q但关闭q接池中所有连接的d则由DBConnectionPoolc负责。在307?23行实现的release() <br />Ҏ供DBConnectionManager调用。该Ҏ遍历freeConnections向量q关闭所有连接,然后从向量中删除q些q接?<br /><br /><br />四、类DBConnectionManager 说明 <br /><br />该类只能创徏一个实例,其它对象能够调用光态方法(也称为类ҎQ获得该唯一实例的引用。如031?36行所C, <br />DBConnectionManagercȝ建构函数是私有的Q这是ؓ了避免其它对象创cȝ实例?<br />DBConnectionManagercȝ客户E序可以调用getInstance()Ҏ获得对该cd一实例的引用。如018?29行所C,cȝ?<br />一实例在getInstance()ҎW一ơ被调用期间创徏Q此后其引用׃直保存在静态变量instance中。每ơ调用getInstance() <br />都增加一个DBConnectionManager的客L序计数。即Q该计数代表引用DBConnectionManager唯一实例的客L序LQ?<br />它将被用于控制连接池的关闭操作?<br />该类实例的初始化工作?46?68行之间的U有Ҏinit()完成。其?getResourceAsStream()Ҏ用于定位q打开外部 <br />文g。外部文件的定位Ҏ依赖于类装蝲器的实现。标准的本地c装载器查找操作L开始于cL件所在\径,也能够搜 <br />索CLASSPATH中声明的路径。db.properties是一个属性文Ӟ它包含定义连接池的键-值对。可供定义的公用属性如下: <br /><br />drivers 以空格分隔的JDBC驱动E序cd?<br />logfile 日志文g的绝对\?<br /><br />其它的属性和特定q接池相养I其属性名字前应加上连接池名字Q?<br /><br /><poolname>.url 数据库的 JDBC URL <br /><poolname>.maxconn 允许建立的最大连接数Q?表示没有限制 <br /><poolname>.user 用于该连接池的数据库帐号 <br /><poolname>.password 相应的密?<br /><br />其中url属性是必需的,而其它属性则是可选的。数据库帐号和密码必d法。用于Windowsq_的db.properties文gCZ <br />如下Q?<br /><br />drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver <br />logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt <br /><br />idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp <br />idb.maxconn=2 <br /><br />access.url=jdbc:odbc:demo <br />access.user=demo <br />access.password=demopw <br /><br />注意在Windows路径中的反斜杠必输?个,q是׃属性文件中的反斜杠同时也是一个{义字W?<br />init()Ҏ在创建属性对象ƈddb.properties文g之后Q就开始检查logfile属性。如果属性文件中没有指定日志文gQ?<br />则默认ؓ当前目录下的DBConnectionManager.log文g。如日志文g无法使用Q则向System.err输出日志记录?<br />装蝲和注册所有在drivers属性中指定的JDBC驱动E序?70?92行之间的loadDrivers()Ҏ实现。该Ҏ先用StringTokenizer <br />drivers属性值分割ؓ对应于驱动程序名U的字符Ԍ然后依次装蝲q些cdƈ创徏其实例,最后在 DriverManager中注?<br />该实例ƈ把它加入C个私有的向量drivers。向量drivers用于关闭服务时从DriverManager取消所有JDBC 驱动E序的注册?<br />init()Ҏ的最后一个Q务是调用U有ҎcreatePools()创徏q接池对象。如109?42行所C,createPools()Ҏ先创?<br />所有属性名字的枚D对象Q即Enumeration对象Q该对象可以惌Z个元素系列,逐次调用其nextElement()Ҏ顺序返 <br />回各元素Q,然后在其中搜索名字以?url”结属性。对于每一个符合条件的属性,先提取其q接池名字部分,q而读 <br />取所有属于该q接池的属性,最后创接池对象q把它保存在实例变量pools中。散列表QHashtablec?Qpools实现q接 <br />池名字到q接池对象之间的映射Q此处以q接池名字ؓ键,q接池对象ؓ倹{?<br />Z于客L序从指定q接池获得可用连接或连接返回给q接池,cDBConnectionManager提供了方法getConnection()?<br />freeConnection()。所有这些方法都要求在参C指定q接池名字,具体的连接获取或q回操作则调用对应的q接池对象完 <br />成。它们的实现分别?51?64行?66?80行?38?49行?<br />?82?07行所C,为实现连接池的安全关闭,DBConnectionManager提供了方法release()。在上面我们已经提到Q所?<br />DBConnectionManager的客L序都应该调用静态方法getInstance()以获得该理器的引用Q此调用增加客L序计数?<br />客户E序在关闭时调用release()可以递减该计数。当最后一个客L序调用release()Q递减后的引用计数?Q就可以?<br />用各个连接池的release()Ҏ关闭所有连接了。管理类release()Ҏ最后的d是撤销所有JDBC驱动E序的注册?<br /><br /><br />五、Servlet使用q接池示?<br /><br />Servlet API所定义的Servlet生命周期cdQ?<br /><br />1) 创徏q初始化ServletQinit()ҎQ?<br />2) 响应客户E序的服务请求(service()ҎQ?<br />3) Servletl止q行Q释放所有资源(destroy()ҎQ?<br /><br />本例演示q接池应用,上述关键步骤中的相关操作为: <br /><br />1) 在init()Q用实例变量connMgr 保存调用DBConnectionManager.getInstance()所q回的引用?<br />2) 在service()Q调用getConnection()Q执行数据库操作Q用freeConnection()连接返回给q接池?<br />3) 在destroy()Q调用release()关闭所有连接,释放所有资源?<br /><br />CZE序清单如下Q?<br /><br />import java.io.*; <br />import java.sql.*; <br />import javax.servlet.*; <br />import javax.servlet.http.*; <br />public class TestServlet extends HttpServlet { <br />private DBConnectionManager connMgr; <br /><br />public void init(ServletConfig conf) throws ServletException { <br />super.init(conf); <br />connMgr = DBConnectionManager.getInstance(); <br />} <br /><br />public void service(HttpServletRequest req, HttpServletResponse res) <br />throws IOException { <br /><br />res.setContentType("text/html"); <br />PrintWriter out = res.getWriter(); <br />Connection con = connMgr.getConnection("idb"); <br />if (con == null) { <br />out.println("不能获取数据库连?"); <br />return; <br />} <br />ResultSet rs = null; <br />ResultSetMetaData md = null; <br />Statement stmt = null; <br />try { <br />stmt = con.createStatement(); <br />rs = stmt.executeQuery("SELECT * FROM EMPLOYEE"); <br />md = rs.getMetaData(); <br />out.println("<H1>职工数据</H1>"); <br />while (rs.next()) { <br />out.println("<BR>"); <br />for (int i = 1; i < md.getColumnCount(); i++) { <br />out.print(rs.getString(i) + ", "); <br />} <br />} <br />stmt.close(); <br />rs.close(); <br />} <br />catch (SQLException e) { <br />e.printStackTrace(out); <br />} <br />connMgr.freeConnection("idb", con); <br />} <br /><br />public void destroy() { <br />connMgr.release(); <br />super.destroy(); <br />} <br />} </td> </tr> </tbody> </table> <img src ="http://www.tkk7.com/songfei/aggbug/62323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/songfei/" target="_blank">天外飞仙</a> 2006-08-08 11:31 <a href="http://www.tkk7.com/songfei/articles/62323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://9522952.com" target="_blank">1000ҹ</a>| <a href="http://meyume.com" target="_blank">AVһ</a>| <a href="http://xx2015.com" target="_blank">ѻɫַ</a>| <a href="http://apguangyu.com" target="_blank">޸պƷһ</a>| <a href="http://zibochanglong.com" target="_blank">þþžAVѾƷ</a>| <a href="http://ninggelang.com" target="_blank">avպavӰƬƷ</a>| <a href="http://8833655.com" target="_blank">þþþþһ</a>| <a href="http://dqmovie.com" target="_blank">AVĻɫ</a>| <a href="http://www621f.com" target="_blank">ĻþƷƵ</a>| <a href="http://hh5151.com" target="_blank">Ƶ</a>| <a href="http://6t23.com" target="_blank">պAVһ</a>| <a href="http://42329c.com" target="_blank">AVӰ߹ۿ</a>| <a href="http://zp0533.com" target="_blank">avҹƷ</a>| <a href="http://www-44334.com" target="_blank">þþѹۿ</a>| <a href="http://wwwwmmmm.com" target="_blank">AVһӰ</a>| <a href="http://222xx8.com" target="_blank">ѹ߹ۿ</a>| <a href="http://kppp4.com" target="_blank">ƷƬѿ</a>| <a href="http://my55572.com" target="_blank">޳AVƬ߹ۿ</a>| <a href="http://yangguang882.com" target="_blank">2018ĻƵ</a>| <a href="http://8mav958.com" target="_blank">һƵ</a>| <a href="http://zfzz008.com" target="_blank">һһƬѲi</a>| <a href="http://tccqdy.com" target="_blank">Ƶ</a>| <a href="http://jsky163.com" target="_blank">avҹƷһ</a>| <a href="http://xjdz8.com" target="_blank">24Сʱձ</a>| <a href="http://6006284.com" target="_blank">Ůۺһ</a>| <a href="http://pj9xx6.com" target="_blank">СƵ߹ۿ</a>| <a href="http://simupiao.com" target="_blank">þþþþëƬѿ</a>| <a href="http://caoporg.com" target="_blank">޸Ƶһ</a>| <a href="http://0330196.com" target="_blank">bbbbbbƵ</a>| <a href="http://857434.com" target="_blank">þùƷ</a>| <a href="http://czshenyue.com" target="_blank">޵һ</a>| <a href="http://dqcjlb.com" target="_blank">avպavŷv</a>| <a href="http://billtsssrvp.com" target="_blank">ŮƷĻ</a>| <a href="http://yisousou.com" target="_blank">޾Ʒ˳߹ۿ </a>| <a href="http://daohang123456.com" target="_blank">޾ƷĻ</a>| <a href="http://whdy888.com" target="_blank">Ʒһ㽶</a>| <a href="http://d8139.com" target="_blank">˳޵һվ߲</a>| <a href="http://f2dai.com" target="_blank">԰߹ۿ޻ɫһƬ </a>| <a href="http://jte-sh.com" target="_blank">ʥһ</a>| <a href="http://znboxcdn304.com" target="_blank">ĻӰѹۿ</a>| <a href="http://www-959kj.com" target="_blank">þѹƵ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>