1\创建文件ora9 ,注意里面的路径 .
#!/bin/bash
#
# (c) denis.klaric@in2.hr
#
# name: /etc/rc.d/init.d/ora9
# des cription: starts and stops oracle 9i database, TNS listener
# http server, and fixes kernel parameters for oracle
. /etc/rc.d/init.d/functions
prog=oracle
start() {
echo -n $"Starting $prog: "
#daemon "startOracle"
su - oracle -c "lsnrctl start"
su - oracle -c "/usr/oracle/product/9.2.0.4/bin/dbstart"
}
stop() {
echo -n $"Stopping $prog: "
#stopOracle
su - oracle -c "lsnrctl stop"
su - oracle -c "/usr/oracle/product/9.2.0.4/bin/dbshut"
}
case $1 in
start)
start
;;
stop)
stop
;;
*)
echo "Usage: ora9 [start|stop]"
;;
esac
2\拷贝到 /etc/init.d/ 中
3\ 运行如下命令
ln -s /etc/init.d/ora9 /etc/rc.d/rc2.d/S99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc3.d/S99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc4.d/S99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc5.d/S99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc0.d/S99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc0.d/K99ora9
ln -s /etc/init.d/ora9 /etc/rc.d/rc6.d/K99ora9
4\修改/etc/oratab 把sid置为Y
5、
sqlplus /nolog
conn sys/pwd as sysdba
create pfile from spfile
6\reboot
Oracle 9.2.0.4 在 Redhat AS3 上安装全过程
折腾我3天 总算是搞定了 同一版本的Oracle 装在不同版本Redhat上 装法都不同 真是麻烦 难怪微软称霸世界 他的产品毕竟好装又好用上网看了别人的装配经历若干 但即使是同一版本的Redhat 每人的配置又都不一样 装法也有差别 Linux的可配置性太高这点不象windows 每个人的windows都差不多 微软没留太多的配置余地给用户 好了说正经的
基本参数
操作系统: Redhat Enterprise Linux as3 默认配置外加所有开发软件包 内存至少512兆 swap分区设置为内存的二倍。不要采用DHCP设置主机名和IP地址,而是“手工设置”。否则会在安装oracle的时候出现如下错误:Thrown when the IP address of a host cannot be determined
Oracle: 9.2.0.4 (注意不是9.2.0.1 这个版本安装后要打补丁升级到 9.2.0.4)
所需的软件
Oracle: 9.2.0.4 安装文件
ship_9204_linux_disk1.cpio.gz
ship_9204_linux_disk2.cpio.gz
ship_9204_linux_disk3.cpio.gz
从网上下载升级补丁包,
所有的补丁说明如下:
p3006854_9204_LINUX.zip 在运行 runInstaller 之前打.
p2617419_210_GENERIC.zip 打其他补丁所需要的工具.
p3119415_9204_LINUX.zip 在升级到9.2.0.4.0之后打.
p3238244_9204_LINUX.zip 用来修agent服务不能启动的错误
安装需要在2个帐户下进行 分别是 root 和 oracle帐户 管理员帐户负责基础设施创建 oracle帐户则负责Oracle软件的安装 帐户切换可用 su
每步安装操作一定要看清楚在那个帐户进行 注意我下面的帐户提示
现在开始
1)先以root登录 在root帐户下进行下面操作
首先准备安装需要的软件包和补丁包 先看安装所需要的软件包是否都装了
a 检察开发软件包 用下面的命令
rpm -q gcc cpp compat-libstdc++ glibc-devel glibc-headers glibc-kernheaders binutils
b 检察安装依赖软件包 查看系统中是否安有以下几个软件包
compat-libstdc++-7.3-2.96.122
compat-gcc-c++-7.3-2.96.122
compat-libstdc++-devel-7.3-2.96.122
compat-db-4.0.14-5
compat-gcc-7.3-2.96.122
setarch-1.3-1.i386.rpm
tcl-8.3.5-92.i386.rpm
nss_db-compat-2.2-20.i386.rpm
如果还没装 它们都在第2和第3张盘上 把它们都装上 保险的做法是把他们都拷到你当前目录下用下面的命令
装过的它会自动跳过
rpm -ivh \
compat-db-4.0.14-5.i386.rpm \
compat-gcc-7.3-2.96.122.i386.rpm \
compat-gcc-c++-7.3-2.96.122.i386.rpm \
compat-libstdc++-7.3-2.96.122.i386.rpm \
compat-libstdc++-devel-7.3-2.96.122.i386.rpm \
openmotif21-2.1.30-8.i386.rpm \
setarch-1.3-1.i386.rpm \
tcl-8.3.5-92.i386.rpm\
nss_db-compat-2.2-20.i386.rpm
注意:在装Redhat时一定要选上 gnome开发软件包 否则将来配置 Oracle http是会出错 没装的话现在装上还来的及
2)还是在root帐户下 准备安装过程中需要的用户和用户组 对就是那个oracle帐户
# groupadd oinstall
# groupadd dba
# useradd -g oinstall -G dba oracle
# passwd oracle
3)还是在root帐户下 准备文件目录:
# mkdir -p /usr/oracle/product/9.2
# mkdir /var/opt/oracle
# chown oracle.dba /var/opt/oracle
# chown -R oracle.dba /usr/oracle
# chmod 777 /var/opt/oracle
3)还是在root帐户下 设置内核参数,调节信号灯及共享内存:
# echo 250 32000 100 128 > /proc/sys/kernel/sem
# echo 1073741824 > /proc/sys/kernel/shmmax
# echo 4096 > /proc/sys/kernel/shmmni
# echo 2097152 > /proc/sys/kernel/shmall
# echo 65536 > /proc/sys/fs/file-max
# echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range
当然为了一开机系统就能自动帮你设好这些参数,也可改动 /etc/sysctl.conf 这个文件,加入以下的语句:
kernel.shmmax = 1073741824
kernel.shmmni = 4096
kernel.shmall = 2097152
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000
保存
设置完成后用命令 more /etc/sysctl.conf |grep kernel.s 检查.
Shmmax: 最大共享内存1GB 物理内存如果小的话可以设置成 536870912
Shmmni: 最小共享内存 4096KB)
4)还是在root帐户下 设置oracle对文件的要求:
编辑文件:/etc/security/limits.conf 加入以下语句:
oracle soft nofile 65536
oracle hard nofile 65536
oracle soft nproc 16384
oracle hard nproc 16384
保存
现在退出root帐户 以oracle帐户登陆
4)在oracle帐户下 设该置帐户环境
打开.bash.profile文件,将如下内容加入:
#oracle 9i
export ORACLE_BASE=/usr/oracle
export ORACLE_HOME=/usr/oracle/product/9.2
export PATH=$ORACLE_HOME/bin:$ORACLE_HOME/Apache/Apache/bin:$PATH
export ORACLE_OWNER=oracle
export ORACLE_SID=db01
export ORACLE_TERM=vt100
export LD_ASSUME_KERNEL=2.4.1
export THREADS_FLAG=native
export LD_LIBRARY_PATH=/usr/oracle/product/9.2/lib:$LD_LIBRARY_PATH
export PATH=/opt/ora9/product/9.2/bin:$PATH
#
# change this NLS settings to suit your country:
# example:
# german_germany.we8iso8859p15, american_america.we8iso8859p2 etc.
#
export LANG=en_US
保存后退出。
然后。退出登录,再次进入,这时候oracle的环境就已经生效了。
4)转到root帐户下 (可用 su root)
随便建立个安装目录把oracle安装文件和补丁都拷进去
解压oracle安装文件
zcat ship_9204_linux_disk1.cpio.gz | cpio -idmv
zcat ship_9204_linux_disk2.cpio.gz | cpio -idmv
zcat ship_9204_linux_disk3.cpio.gz | cpio -idmv
解压完后看见Disk1,Disk2,Disk3这3个目录
打安装前补丁 p3006854_9204_LINUX.zip 用下面的命令
# unzip p3006854_9204_LINUX.zip
Archive: p3006854_9204_LINUX.zip
creating: 3006854/
inflating: 3006854/rhel3_pre_install.sh
inflating: 3006854/README.txt
...
# cd 3006854
# sh rhel3_pre_install.sh
退出root帐户
5)回到oracle帐户下
进到Disk1目录运行
./runInstaller
启动安装界面
- Welcome Screen: Click Next
- Inventory Location: Click Next
- Unix Group Name: Use "oinstall" and click Next
会提示运行 /tmp/orainstRoot.sh, 运行它然后继续
- File Locations: Use default values
- Available Products: Select "Oracle9i Database 9.2.0.4"
- Installation Types: 选择安装类型是“通用”除非你有特别要求 如数据仓库 或不想要产生默认数据库
- 输入全局数据库名: 我一般设为和下面SID一样
- 数据文件的存放位置: 我采用的是默认位置,点“Next”;
出现安装组件的选择结果,这时点“Install”,开始安装,复制文件,进度条在一点一点的增加,当安装并link完后,会提示运行root.sh 运行它然后继续
出现配置工具界面,默认数据库正确配置完毕后会自动产生2个数据库管理员帐户 SYS 和 SYSTEM 分别设置密码然后继续
agent服务不能配置成功,忽略不用管,在下面修复。DBCA,NETCA,HTTP都正确配置完毕哦。下面开始修复错误。
6)转到root帐户下 (可用 su root)
先加入下面2个环境变量
#export ORACLE_BASE=/usr/oracle
#export ORACLE_HOME=/usr/oracle/product/9.2
先解压补丁工具 p2617419_210_GENERIC.zip 这是打其他补丁所需要的工具opatch.
# unzip p2617419_210_GENERIC.zip
Archive: p2617419_210_GENERIC.zip
creating: OPatch/
creating: OPatch/docs/
inflating: Opatch/docs/FAQ
......
inflating: README.txt
# pwd
解压所在目录
# export PATH=$PATH:解压所在目录/OPatch:/sbin
安装p3119415_9204_LINUX.zip 补丁
# unzip p3119415_9204_LINUX.zip
Archive: p3119415_9204_LINUX.zip
creating: 3119415/
......
inflating: 3119415/README.txt
# cd 3119415
# opatch apply
安装p3238244_9204_LINUX.zip补丁
unzip p3238244_9204_LINUX.zip
# cd 3238244
...
# opatch apply
补丁修复完成,需要relinked一个.mk文件。
回到oracle帐户下
$ cd $ORACLE_HOME/network/lib
$ make -f ins_oemagent.mk install
现在在运行agentctl start,看是不是可以成功运行agent服务了啊,可以用stop、status来停止此服务或者检查服务的状态
好了全部的安装就算成功了.
祝贺你,恶梦结束了
要配置数据库用
$dbca
要启动企业管理器
$oemapp console
看看能不能连上刚才创建的数据库
注意:下次从新开机后企业管理器中打开数据库报ORA-12541:TNS:no listener错误
这是因为监听服务(listener)第一次是安装程序为你启动的 以后你得自己启动 用下面的命令
$lsnrctl start
我一直认为jsf必定会成为MS的 Net Freamwork的竞争对手。但,jsf尚在发展阶段。至少目前不会。
JSF使用
原文地址:http://www.javaworld.com/javaworld/jw-07-2004/jw-0719-jsf.html
使用JavaServer Faces(JSF)、Spring Framework和Hibernate建立一个真实的Web应用程序
内容概要
使用JSF建立一个真实的Web应用程序不是没有意义的任务,这篇文章介绍了如何将JSF与Sping Framework和Hibernate集成,并且给出了使用这些技术建立这个真实的Web应用程序的最佳实践和设计指导
JavaServer Faces(JSF)技术是J2EE应用程序的一个新的用户接口框架,它非常适合基于MVC(Model-View-Controller)体系结构的应用程序。已经有大量的文章介绍JSF。然而,很多文章都是站在理论研究的层面上,没有挑战一个真实的企业开发。很多问题没有解决,例如,JSF怎样全面适合MVC体系结构?JSF如何与其他JAVA框架集成?业务逻辑应该放在JSF的backing beans里面吗?怎样处理JSF里面的安全问题?最重要的是你怎样使用JSF建立一个真实的Web应用程序?
这篇文章涉及所有这些问题。它向你展示如何集成其他特定的Java框架,Spring Framework和Hibernate,它示范怎样去创建一个叫JCatalog的Web应用程序,一个在线的产品目录系统。这篇文章使用JCatalog例子,介绍了Web应用程序设计的每一个阶段,包括业务需求收集,分析,技术选择,高层体系结构和详细设计。这篇文章论述了JCatalog里面好的和不好的技术,示范了应用程序设计中一些关键方面的方法和步骤。
这篇文章是写给正在从事基于J2EE Web应用程序的Java架构师,开发者,它不是对JSF、Spring Framework和Hibernate的入门教程。如果您对这些领域不熟悉,请参考文章最后的资源链接。
例子应用程序的功能需求
这篇文章的例子应用程序JCatalog是一个真实的Web应用程序,例子足够现实是为了决定应用程序架构而进行意味深长的讨论的基础。我通过介绍JCatalog项目的需求开始。我在这里谈到后面贯穿于整个文章的内容是为了演示技术选择和体系结构设计。
设计Web应用程序的第一步是收集系统的功能需求,这个例子应用程序是一个典型的电子商务应用系统。用户能浏览产品目录和查看产品细节,管理员能管理产品目录。功能还可以增加,举例来说,为了开发一个成熟的电子商务系统,可以添加库存管理和订单处理的功能。
用例
用例分析被用于去访问例子应用程序的功能需求,图1是应用程序的用例图。
图1 用例图
一个用例图确定在一个系统中的参与者以及参与者可以执行的操作。例子应用中7个用例必须被实现。参与者中的User能浏览产品目录和察看产品细节。一旦用户以Administrator身份连接到系统,他就能创建新产品,编辑存在的产品,删除老的产品。
业务规则
JCatalog 必须符合下面的业务规则:
每个产品有一个唯一的产品ID
每个产品至少属于一个目录
产品ID一旦被创建就不能改变
假定
对于产品的设计和实现,我们做下面的假定。
英语是默认语言;不要求国际化
目录中不超过500种产品
目录的更新不频繁
页面流
图2显示了所有JCatalog的页面和它们之间的转换。
图2 页面流图
应用程序有两组页面:公共的国际互联网和管理员的企业内部网。企业内部网只有对那些成功登陆到系统的用户有效。产品概要页面是公用的,它作为产品目录的内容包含在一个HTML框架里面。产品列表是一个特殊的目录,只能被管理员看见,它包含创建、编辑和删除产品的链接。
图3是目录页的一个模型。理想情况下,每一个页面所有的控制和必要的内容明细的模型应该被包含在需求文档里面。
图3 目录页面模型
高级体系结构设计
下一步的设计是Web应用程序的高级体系结构设计,它包括将应用程序细分成功能组件以及将这些组件划分到各自所属的层。高级体系结构设计独立于使用的技术。
多层体系结构
一个多层体系结构将整个系统划分成清晰的单元——客户端、表示层、业务逻辑层、集成层和企业信息系统(EIS),这保证了清晰的责任划分以及可维护性和可扩展性。三层或多层系统已经被证明比没有业务逻辑层的客户-服务器系统具有更多的可升级性和柔韧性。
客户端是数据模型被消费和呈现的地方。对于一个Web应用程序,客户层通常是Web浏览器。基于浏览器的瘦客户不包含表示逻辑;它依赖于表示层。
表示层使用业务逻辑层为用户服务,它知道怎样去处理一个客户请求,怎样去和业务逻辑层结合以及怎样去选择下一个试图去显示。
业务逻辑层包含一个应用程序的业务对象和业务服务。它从表示层接受请求,基于请求处理业务逻辑,作为访问EIS层资源的的中介。业务逻辑层组件使用许多系统级别的服务,例如,安全管理、事物管理和资源管理。
集成层是业务逻辑层和EIS层之间的桥梁。它封装了与EIS层相结合的逻辑。有时,集成层和业务逻辑层的结合是作为中间层被提到。
应用程序数据在EIS层被持久化,包括关系数据库,面向对象数据库和遗留系统。
JCatalog 的体系结构设计
图4显示了JCatalog的高级体系结构设计以及它怎样适合多层体系结构。
|
图4 高级体系结构图
应用程序使用了一个多层的非分布式的体系结构,图4显示应用程序层和每一层技术选择的划分。它也用于应用程序的部署图。对于一个可配置的体系结构,表示层、业务逻辑层和集成层被定位在同样的Web容器。定义良好的接口隔离了每一层的职责。可配置的体系结构使应用程序简单和可升级。
对于表示层,经验告诉我们,最好的实践是选择一个存在的,被验证的Web应用框架,远比设计开发一个定制的框架好。我们有几个Web应用框架可供选择,举例来说,Struts、WebWork和JSF。对于JCatalog项目,我们使用JSF。
对于业务逻辑层,不是使用EJB(Enterprise JavaBeans)就是使用POJO(plain old Java objects)。如果应用程序是分布式的,EJB具有远程接口是一个较好的选择。因为JCatalog是一个典型的没有远程访问请求的Web应用程序,POJO在Spring框架的帮助下,用于实现业务逻辑层。
Pure JDBC(Java Database Connectivity):这是最灵活的实现方法;然而,低级的JDBC和不好的JDBC代码工作是麻烦的,执行的不好。
Entity beans:一个容器管理持久化(CMP,container-managed persistence)的entity bean是隔离数据访问代码和处理O/R(object- relational) mapping数据持久化的昂贵的方法。它是一个以应用服务器为中心的解决办法。一个entity bean不和特定的数据库紧耦合,但是应用程序和EJB容器进耦合。
O/R mapping framework:一个O/R影射的框架采用以对象为中心的方法实现数据持久化。一个以对象为中心的应用程序是容易开发和高度轻便的。在这个领域内存在几个框架——JDO(Java Data Objects),Hibernate,Toplink。CocoBase是一个新的例子。在例子应用程序中我们使用HIbernate。
现在,让我们讨论将应用程序的每一个层联合起来设计的问题。因为JSF相对来说是一个新技术,我强调一下它的使用。
表现层和JavaServer Faces(JSF)
表现层收集用户输入,呈现数据,控制页面导航,代替用户与业务逻辑层交互。表现层也能校验用户输入,维护应用程序的会话状态。下面的章节,我讨论表现层的设计考虑和模式以及我选择JSF去实现JCatalog项目的表现层的原因。
MOdel-View-Controller(MVC)
MVC是Java蓝皮书(BluePrints)中推荐的交互式应用程序体系结构设计模式。MVC分别设计关注的问题,因此减少了代码的重复,集中控制,使应用程序更具扩展性。MVC也帮助开发者使用不同的技术集合,集中他们核心的技术,通过定义清晰的接口进行合作。MVC是表现层的体系结构设计模式。
JavaServer Face
JSF是一个基于Java的Web应用程序服务端的用户接口组件框架。JSF包括表示UI组件和管理其状态的API;处理事件,服务端校验,数据转换;定义页面导航;支持国际化和可访问性;提供所有这些特点的扩展能力。它还包括两个为JSP定制的标签库,一个用于表示JSP页面内的UI组件,一个用于配置服务端的对象组件。
JSF和MVC
JSF很适合基于MVC的表现层体系结构。它提供动作和表现之间清楚地划分。它影响了UI组件和Web层概念,不限定你去使用特定的脚本技术或者标记语言。
JSF backing beans 是model层(后面的章节有关于backing beans 的更多内容)。它们也包含动作,这是控制层的扩展,代理用户对业务逻辑层的请求。请注意,从整体应用程序的体系结构来看,业务逻辑层也能被作为Model层提到。使用JSF定制标签的JSP页面是视图层。Faces Servlet提供控制者的功能。
为什么用JSF
JSF不仅仅只是另一个Web框架,下面是JSF与其他Web框架不同的特点:
象Swing一样面向对象的Web应用程序开发:服务端有状态的UI组件模型,具有事件监听和操作者,开始了面向对象Web应用程序开发。
Backing-bean管理:Backing beans是页面中JavaBeans组件和UI组件的联合。Backing-bean管理UI组件对象定义和对象执行应用程序特殊过程以及控制数据的分离。JSF在正确的范围内执行存储和管理这些backing-bean实例。
可扩展的UI组件模型:JSF UI组件是组成JSF应用程序用户接口可配置、可复用的元素。你能扩展标准的UI组件和开发更多的复杂组件。举例来说,菜单条和树型构件。
灵活的表现模型:一个renderer分隔一个UI组件的功能和视图。多个renderer能被创建,用于定义相同或不同客户端上同样组件的不同外观。
可扩展的转化和校验模型:基于标准的转换者和校验者,你能开发定制的转换者和校验者,它们提供最好的模型保护。
尽管JSF很强大,但是现在还不成熟。组件、转换者和校验者是JSF基本的。每一个校验模型不能处理组件和校验者之间多对多的校验。另外,JSF定制标签不能和JSTL(JSP Standard Tag Library)无缝结合。
在下面的部分,我讨论用JSF实现JCatalog项目时几个关键方面和设计决定。首先讨论JSF中managed beans和backing beans的定义和使用。然后,我介绍JSF中怎样处理安全、分页、缓存、文件上传、校验和错误消息定制。
Managed bean,backing bean,view object和domain object model
JSF介绍了两个新的术语:managed bean 和 backing bean。JSF 提供一个强大的managed-bean工厂。被JSF执行的JavaBean对象管理被叫做managed beans。一个managed bean描述一个bean怎样被创建和管理。它没有利用bean的功能性。
Backing bean 定义页面特性和处理逻辑与UI组件的联合。每一个backing-bean属性被绑定到组件实例或者它的值中的一个。一个backing bean也定义一个组件可执行的功能的集合,例如,校验组件的数据,处理组件触发事件,组件激活时与导航相关的执行过程。
一个典型的JSF应用程序在应用程序的每一个页面中连接一个backing bean。然而,有时在真实的世界里,强迫一个backing bean和一个页面一对一的关系不是一个理想的解决方案。它能造成象代码重复这样的问题。在真实世界的场景里,几个页面可能需要共享在后台的同样的backing bean。例如,在JCatalog项目里,CreateProduct和EditProduct页面共享同样的ProductBean的定义。
一个试图对象是在表示层明确使用的模型对象。它包含了必须显示在视图层的数据和校验用户输入,处理事件和与业务逻辑层相结合的逻辑。backing bean是基于JSF应用程序的视图对象。
在这篇文章中Backing bean 和视图对象是可交换的术语。
比较Struts中的Actionform和Action,在JSF中开发backing beans遵循面向对象设计的最好实践。一个backing bean不仅包含视图数据,也包含与数据相关的行为。在Struts 中,Action 和ActionForm包含数据和逻辑分离。
我们都听说过域对象模型。那么,域对象模型和视图对象有什么不同呢?在一个简单的Web应用程序里,一个域对象模型能被用于所有的层,然而,在一些复杂的Web应用程序里面,一个单独的视图对象模型需要被使用。域对象模型是关于业务对象,应该归入业务逻辑层。它包含特定业务对象相关的业务数据和业务逻辑。一个视图对象包含特定数据和行为的表示。JCatalog项目的ProductListBean提供了一个好的例子。它包含表示层数据和逻辑细节,举例来说,与分页相关的数据和逻辑。从域对象模型分离视图对象的缺点是数据映射必须发生在两个对象模型之间。在JCatalog项目中,ProductBeanBuilder和UserBeanBuilder使用基于反射的Commons BeanUtils去实现数据映射。
安全
当前,JSF没有内置的安全特征。例子的安全需求是基本的:用户连接到管理员使用的公司内部网需要的认证是基于用户名和密码,不需要授权。
在JSF里面几个处理用户认证的方法已经被提出:
Use a base backing bean:这个解决方 案是简单的。然而,它使backing beans与特殊的遗产层次绑定。
Use JSF ViewHandler decorator:这种方法使安全逻辑紧紧地加上一个特殊的Web层技术。
Use a servlet filter:一个JSF 应用程序与其他基于Java的Web应用程序不同。它在一个恰当的地方使用一个过滤器处理认证检查。这种方法使Web应用程序中的认证逻辑减弱了。
在例子应用程序中,SecurityFilter类处理用户认证。当前,受保护的资源只有三个页面,为了简单,它们被硬编码在Filter类里面。可以通过扩展安全规则来改进它,把受保护的资源放到配置文件中。
分页
应用程序的目录页需要分页。表现层能处理分页,这意味着所有数据必须被重新得到存储在这层。分页也能在业务逻辑层、集成层甚至是EIS层处理。JCatalog项目的假定是在目录中的产品不超过500种。所有产品信息适合保存在用户session中。分页逻辑存在ProductListBean类中。与分页有关的参数“每页的产品”通过JSF的managed-bean工具配置。
缓存
缓存是Web应用程序中改善性能的众多重要技术中的一种。缓存能在应用程序体系结构内的许多层完成。体系结构中的一层减少调用它下面的层时,缓存是非常有益的。JSF managed-bean工具使在表现层实现缓存更容易。通过改变一个managed bean的范围,包含在managed bean中的数据能在不同的范围内缓存。
例子应用程序使用二级缓存。第一级缓存在业务逻辑层里面。CachedCatalogServiceImpl类维护所有产品和目录的读/写缓存。Spring 管理的类作为一个单独服务bean。所以,一级缓存是一个应用程序范围的读/写缓存。
对于简单的分页逻辑和将来应用程序速度的提高,表现层的会话范围内的产品也被缓存。每个用户维护他session里面自己的ProductListBean。缺点是占用系统内存和存在旧数据。在一个用户session的持续时间里,如果管理员更新了目录,用户可能会看到旧的目录数据。然而,基于这样的假定,目录中部超过500种产品,而且目录更新不频繁,我们应该能够忍受这些缺点。
文件上传
目前,JSF的Sun参考实现中不支持文件上传。Struts有很好的文件上传能力,然而,Struts外观集成库是必须使用。 在JCatalog项目中,一个图片与每个产品关联。一个用户创建一个新的产品之后,必须上传与之相关的图片。图片保存在应用服务器的文件系统里面。产品ID是图片名.
例子应用程序使用<input type="file">,Servlet 和Jakarta通用的文件上传API,实现一个简单的文件长传功能。这个功能使用两个参数:产品图片路径和图片上传结果页面。它们都通过ApplicatonBean配置。请参考FileUploadServlet类的详细资料。
校验
JSF具有的标准校验是简单基本的,不能满足真实的需求。开发自己的JSF校验是容易的。我在例子应用程序中使用定制标签来开发SelectedItemsRange校验。它校验通过UISelectMany UI组件选择的项目数量:
<h:selectManyListbox value="#{productBean.selectedCategoryIds}" id="selectedCategoryIds">
<catalog:validateSelectedItemsRange minNum="1"/>
<f:selectItems value="#{applicationBean.categorySelectItems}" id="categories"/>
</h:selectManyListbox>
更多的详细资料请参考例子应用程序。
错误消息定制
在JSF里面,你可以设置资源包定制转换和校验时的错误消息。资源包被设置在faces-config.xml里面:
<message-bundle>catalog.view.bundle.Messages</message-bundle>
The error message's key-value pairs are added to the Message.properties file:
#conversion error messages
javax.faces.component.UIInput.CONVERSION=Input data is not in the correct type.
#validation error messages
javax.faces.component.UIInput.REQUIRED=Required value is missing.
业务逻辑层和Spring Framework
业务对象和业务服务在业务逻辑层。一个业务对象不仅包含数据,也有与特定对象关联的逻辑。在例子应用程序中标识了三个业务对象:Product,Category和User.
业务服务与业务对象相结合,提供高级的业务逻辑。一个包含直接使用的服务接口的标准的业务接口层应该被定义。在Spring Framework的帮助下,POJO实现了Jcatalog项目业务逻辑层。有两个业务服务:CatalogService包含与目录管理相关的业务逻辑,UserService包含了用户管理逻辑。
Spring是基于控制反转概念(IOC,inversion of control)。在例子应用程序中使用的Spring特征包括:
Bean management with application contexts:Spring能有效地组织我们的中间层对象,垂直处理。Spring 能避免一个实体功能的分解,促进好的面向对象设计实现,举例来说,接口设计。
Declarative transaction management:Spring 使用AOP(aspect-oriented programming)去描述不使用EJB容器的声明性事务处理。这种方法,事务管理能被应用到任何POJO。Spring事务管理不和JTA(Java Transaction API)绑定,使用不同的事物策略工作。在例子应用程序中声明性事务管理Hibernate中的事务。
Data-access exception hierarchy:Spring提供一个值得回味的异常层次代替SQLException。使用Spring数据访问异常层次,Spring数据访问异常翻译者必须在Spring配置文件里面定义:
<bean id="jdbcExceptionTranslator"
class= "org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
在例子应用程序中,如果插入的一个新产品的ID是重复的,一个 DataIntegrityViolationException 会被抛出。这个异常会被捕获然后作为DuplicateProductIdException被抛出。这种方法,DuplicateProductIdException能处理不同的数据访问异常。
Hibernate integration:Spring不强迫我们使用它强大的JDBC抽象特征。它和O/R映射框架集成的很好,尤其是Hibernate。Sping提供有效的、安全的Hibernate会话操作。在应用程序上下文操作Hibernate的配置SessionFactories 和JDBC数据源,使应用程序容易测试。
集成层和HIbernate
Hibernate是一个开源O/R映射框架,它减少使用JDBC API的需要。Hibernate支持所有主流的SQL数据库管理系统。Hibernate Query Language是SQL面向对象的最小的扩展来设计的,在对象和关系世界间提供了一个优雅的桥。Hibernate提供数据恢复和更新的工具,事务管理,数据连接池,programmatic and declarative queries,声明实体关系管理。
Hibernate和其他O/R映射框架相比入侵性较小。使用反射和运行时产生字节码,SQL在系统开始时产生。它允许我们开发符合Java习惯的持久对象,包括联合,继承,多态,聚合和Java集合框架。在例子应用程序中的业务对象是POJO,不需要实现Hibernate的特殊接口。
Data Access Object (DAO)
JCatalog项目使用DAO模式。这个模式抽象和封装了所有对数据源的访问。应用程序有两个DAO接口。CatalogDao和UserDao。它们的实现类是HibernateCatalogdaoImpl和HibernateUserDaoImpl包含与Hibernate相关的管理和持久化数据逻辑。
实现设计
现在,让我把每件事情都串起来,实现JCatalog项目。你可以冲资源列表中下载应用程序的完整源代码。
数据库设计
我们为例子应用程序创建指定目录的结构,它包含4个表,如图5:
|
图5 数据结构图
类设计
图6图解了JCatalog项目的类图
图6 类图
面向接口编程贯穿于整个设计。在表现层,四个bean被使用:ProductBean, ProductListBean, UserBean和 MessageBean。业务逻辑层包含两个服务(CatalogService and UserService)和三个业务对象(Product, Category, and User)。集成层包括两个DAO接口和它们的Hibernate实现。Spring application contexts 包含和管理业务逻辑层和集成层的很多object beans。ServiceLocator使JSF和业务逻辑层结合到一起。
Wire everything up
因为这篇文章篇幅的限制,我们只看一个用例。CreateProduct用例示范了怎样将每件事情串起来建造应用程序。深入细节以前,让我们使用一个序列图(图7)示范所有层端到端的整合:
图7 CreateProduct用例的序列图
现在,让我们通过对每一层的介绍讨论如何实现CreateProduct用例的更多细节。
表现层
表现层的实现包括创建JSP页面,定义页面导航,创建和配置backing beans,将JSF与业务逻辑层结合。
JSP page:createProduct.jsp是创建新产品的页面。它包括UI组件和捆绑这些组件的ProductBean。ValidateItemsRange自定义标签检验用户选择目录的数目。每个新产品至少有一个目录被选择。
Page navigation:应用程序的导航定义在应用程序的配置文件里面,faces-navigation.xml。CreateProduct定义的导航规则是:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>createProduct</from-outcome>
<to-view-id>/createProduct.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/createProduct.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/uploadImage.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>retry</from-outcome>
<to-view-id>/createProduct.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>cancel</from-outcome>
<to-view-id>/productList.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Backing bean: ProductBean不仅包含了页面中UI组件与数据映射的属性,也包含三个actions:createAction,editAction和deleteAction。这是createAction()方法的代码:
public String createAction() {
try {
Product product = ProductBeanBuilder.createProduct(this);
//Save the product.
this.serviceLocator.getCatalogService().saveProduct(product);
//Store the current product id inside the session bean.
//For the use of image uploader.
FacesUtils.getSessionBean().setCurrentProductId(this.id);
//Remove the productList inside the cache.
this.logger.debug("remove ProductListBean from cache");
FacesUtils.resetManagedBean(BeanNames.PRODUCT_LIST_BEAN);
} catch (DuplicateProductIdException de) {
String msg = "Product id already exists";
this.logger.info(msg);
FacesUtils.addErrorMessage(msg);
return NavigationResults.RETRY;
} catch (Exception e) {
String msg = "Could not save product";
this.logger.error(msg, e);
FacesUtils.addErrorMessage(msg + ": Internal Error");
return NavigationResults.FAILURE;
}
String msg = "Product with id of " + this.id + " was created successfully.";
this.logger.debug(msg);
FacesUtils.addInfoMessage(msg);
return NavigationResults.SUCCESS;
}
在这个action里面,基于ProductBean的一个Product业务对象被建立。ServiceLocator查询CatalogService。最后,createProduct的请求被委派给业务逻辑层的CatalogService。
Managed-bean declaration: ProductBean必须在JSF的配置资源文件faces-managed-bean.xml中配置:
<managed-bean>
<description>
Backing bean that contains product information.
</description>
<managed-bean-name>productBean</managed-bean-name>
<managed-bean-class>catalog.view.bean.ProductBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.productId}</value>
</managed-property>
<managed-property>
<property-name>serviceLocator</property-name>
<value>#{serviceLocatorBean}</value>
</managed-property>
</managed-bean>
ProductBean有一个请求的范围,这意味着如果ProductBean在JSP页面内引用JSF执行为每一个请求创建ProductBean实例的任务。被管理的ID属性与productId这个请求参数组装。JSF从请求得到参数,设置managed property。
Integration between presentation and business-logic tiers: ServiceLocator抽象了查询服务的逻辑。在例子应用程序中,ServiceLocator被定义成一个一个接口。接口被JSF managed bean实现为ServiceLocatorBean,它从Spring application context查询服务:
ServletContext context = FacesUtils.getServletContext();
this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
this.catalogService = (CatalogService)this.lookupService(CATALOG_SERVICE_BEAN_NAME);
this.userService = (UserService)this.lookupService(USER_SERVICE_BEAN_NAME);
ServiceLocator被定义为BaseBean中的一个属性。JSF managed bean容易连接ServiceLocator执行必须访问ServiceLocator的那些managed beans。使用了Inversion of control(IOC,控制反转)
业务逻辑层
定义业务对象,创建服务接口和实现,在Spring中配置这些对象组成了这一层的任务。
Business objects: 因为Hibernate提供了持久化,Product和Category业务对象需要为它们包含的所有属性提供getter和setter方法。
Business services:CatalogService接口定义了所有与目录管理有关的服务:
public interface CatalogService {
public Product saveProduct(Product product) throws CatalogException;
public void updateProduct(Product product) throws CatalogException;
public void deleteProduct(Product product) throws CatalogException;
public Product getProduct(String productId) throws CatalogException;
public Category getCategory(String categoryId) throws CatalogException;
public List getAllProducts() throws CatalogException;
public List getAllCategories() throws CatalogException;
}
CachedCatalogServiceImpl服务的接口实现,它包含CatalogDao对象的一个setter。Spring将CachedCatalogServiceImpl 和CatalogDao连接在一起。因为我们提供了接口,所以对实现的依赖不是很紧密。
Spring configuration: 下面是CatalogService的Spring comfiguration:
<!-- Hibernate Transaction Manager Definition -->
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<!-- Cached Catalog Service Definition -->
<bean id="catalogServiceTarget" class="catalog.model.service.impl.CachedCatalogServiceImpl" init-method="init">
<property name="catalogDao"><ref local="catalogDao"/></property>
</bean>
<!-- Transactional proxy for the Catalog Service -->
<bean id="catalogService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="target"><ref local="catalogServiceTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
Spring声明事务管理是在CatalogService. CatalogService 里面设置,它能实现不同CatalogDao。Spring创建并管理单体实例Catalogservice,不需要工厂。
现在,业务逻辑层准备好了,让我们将它与集成层整合。
Integration between Spring and Hibernate:下面是HibernateSessionFactory的配置:
<!-- Hibernate SessionFactory Definition -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>catalog/model/businessobject/Product.hbm.xml</value>
<value>catalog/model/businessobject/Category.hbm.xml</value>
<value>catalog/model/businessobject/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</prop>
</props>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
CatalogDao使用HibernateTemplate集成Hibernate和Spring.下面是HibernateTemplate的配置:
<!-- Hibernate Template Defintion -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
<property name="jdbcExceptionTranslator"><ref bean="jdbcExceptionTranslator"/></property>
</bean>
集成层
Hibernate使用一个XML配置文件去映射业务对象到关系型数据库。在JCatalog项目中,Product.hbm.xml表示Product业务对象的映射。Category.hbm.xml用于业务对象Category。配置文件和相应的业务对象在同样的目录下。下面是Product.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="catalog.model.businessobject">
<class name="Product" table="product">
<id name="id" column="ID" unsaved-value="null">
<generator class="assigned"/>
</id>
<property name="name" column="NAME" unique="true" not-null="true"/>
<property name="price" column="PRICE"/>
<property name="width" column="WIDTH"/>
<property name="height" column="height"/>
<property name="description" column="description"/>
<set name="categoryIds" table="product_category" cascade="all">
<key column="PRODUCT_ID"/>
<element column="CATEGORY_ID" type="string"/>
</set>
</class>
</hibernate-mapping>
CatalogDao通过Spring使用HibernateTemplate连接:
<!-- Catalog DAO Definition: Hibernate implementation -->
<bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl">
<property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property>
</bean>
结论
这篇文章介绍了怎样将JSF集成到Spring Framework和Hibernate,建立了一个真实的应用程序。这三种技术的联合提供了一个可靠的Web应用程序开发框架。一个多层体系结构应该做为Web应用程序的高级体系结构。JSF很适合MVC设计模式,能够被用于实现表示层。Spring框架能被用于业务逻辑层去管理业务对象,提供声明性事务管理和资源管理。Spring与Hibernate结合的很好。Hibernate是一个强有力的O/R映射框架,能够提供集成层的服务。
通过将Web应用程序划分成不同的层和面向接口编程,每一层的技术可以被取代。例如, 在表示层Struts能取代JSF,在集成层JDO能取代Hibernate。应用程序层之间的整合不是没有意义的,使用inversion of control和Service Locator设计模式能使这个工作容易。JSF提供了其他框架,如Struts所缺少的功能。然而,这不意味着你应该立刻抛弃Struts而开始使用JSF 。无论怎样,你的项目是否使用JSF作为你的Web框架,取决于你项目的状态和功能需求以及团队专家的意见。
Resources
Download the JCatalog project sample application:
http://www.javaworld.com/javaworld/jw-07-2004/jsf/jw-0719-jsf.zip
Official JavaServer Faces site:
http://java.sun.com/j2ee/javaserverfaces/index.jsp
A good JSF tutorial can be found in The J2EE 1.4 Tutorial (Chapters 17 to 21):
http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html
More articles and books on JSF:
http://jsfcentral.com/reading/index.html
Official Spring Framework site:
http://www.springframework.org
Good introduction to the Spring Framework by Rod Johnson:
http://www.theserverside.com/articles/article.tss?l=SpringFramework
Rod Johnson's book Expert One-on-One J2EE Design and Development (Wrox, October 2002; ISBN: 0764543857) is the corner stone of the Spring Framework:
http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764543857.html
Official Hibernate site:
http://www.hibernate.org
Online documentation of Hibernate:
http://www.hibernate.org/hib_docs/reference/en/html/
Introduction to the integration between the Spring Framework and Hibernate:
http://hibernate.bluemars.net/110.html
"Designing Enterprise Applications with the J2EE Platform, Second Edition" is a good introduction to the multitiered architecture and MVC design pattern:
http://java.sun.com/blueprints/guidelines/designing_enterprise_applications_2e/index.html
Commons BeanUtils:
http://jakarta.apache.org/commons/beanutils/
Commons FileUpload:
http://jakarta.apache.org/commons/fileupload/
For more on JavaServer Faces, read the following JavaWorld articles by David Geary:
"A First Look at JavaServer Faces, Part 1" (November 2002)
"A First Look at JavaServer Faces, Part 2" (December 2002)
"JavaServer Faces, Redux" (November 2003)
Browse the JavaServer Pages section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-jsp-index.shtml
Browse the Enterprise Java section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-enterprise-index.shtml
一个简单的JSF例子(A simple JavaServer Faces example)
Figures 2a, 2b, and 2c show a very simple JSF application. The application's opening page contains a link that starts the application. That link points to a JSP page that displays a simple form. Because this simple application does not perform validation, you can click the Log In button without filling in the name and password fields, which will transport you to another JSP page that welcomes you to JavaServer Faces.
图2a、2b、2c展示了一个简单的JSF应用。这个应用的入口页面包含一个启动应用的链接。这个链接指向一个显示一个简单表单的JSP页面。由于这个简单的应用不进行验证操作,所以你在表单的姓名和密码域中不用输入任何内容直接点击Log In按钮,你将被引导到另外一个欢迎你使用JSF的JSP页面。
图 2a 一个简单的JSF应用
图 2b JSF登录界面
图 2c欢迎信息
First, let's explore the logistics of implementing this simple application,
and JavaServer Faces applications in general. JSF requires the following jar files in the WEB-INF/lib directory:
首先,我们浏览一下这个简单的应用和通常的JSF应用需要的支持。JSF需要在WEB-INF/lib目录下存放有一下文件:
WEB-INF/lib/commons-beanutils.jar
WEB-INF/lib/commons-collections.jar
WEB-INF/lib/commons-digester.jar
WEB-INF/lib/commons-logging-api.jar
WEB-INF/lib/jsf-api.jar
WEB-INF/lib/jsf-ri.jar
WEB-INF/lib/jstl.jar
WEB-INF/lib/standard.jar
The jar files listed above are all you need for JSF applications. Even though, as we will see shortly, JSF applications typically use JSP tags implemented by the JSF implementation, there are no separate tag library descriptor (TLD) files because that information is contained in the jar files.
JSF应用需要的所有内容就是上面列举的这些jar文件。当然,我们很快会注意到,JSF应用通常会使用JSF实现中实现的JSP 标签,但是并不需要额外的标签库描述符(TLD)因为这些信息也包含在上面的jar文件中。
Here's a listing of the other files that comprise the application shown in Figure 2:
下面是一些我们这个JSF应用需要的其他文件的清单。
WEB-INF/web.xml
WEB-INF/classes/com/sabreware/listeners/SimpleContextListener.java
WEB-INF/classes/com/sabreware/appHandlers/SimpleApplicationHandler.java
/index.html
/index.jsp
示例1 WEB-INF/web.xml
Example 1. WEB-INF/web.xml
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Context Listener creates and sets the application handler -->
<listener>
<listener-class>
com.sabreware.listeners.SimpleServletContextListener
</listener-class>
</listener>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
The deployment descriptor listed above declares four things:
A servlet context listener
A controller servlet
A mapping for the controller servlet
A welcome file
上面的部署描述符声明了四项内容:
1. 一个Servlet环境(Context)监听器
2. 一个控制器Servlet
3. 控制器Servlet的映射
4. 一个欢迎页面
The deployment descriptor listed in Example 1 associates the JSF controller servlet with the URL /faces/*, which causes the servlet container to map all URLs that start with /faces to the JSF controller servlet. JSF uses the controller servlet to control the JSF lifecycle.
部署描述符将/faces/*这样的URL请求和JSF控制器servlet关联起来,这使得servlet容器将把所有以/faces开头的URL请求映射到这个JSF控制器servlet页面。JSF使用这个控制器servlet控制JSF处理流程。
示例2 servlet运行环境监听器
Example 2. WEB-INF/com/sabreware/listeners/SimpleServletContextListener
- package com.sabreware.listeners;
-
- import javax.servlet.*;
- import javax.faces.*;
- import javax.faces.lifecycle.*;
- import com.sabreware.appHandlers.SimpleApplicationHandler;
-
- public class SimpleServletContextListener implements ServletContextListener {
- public void contextInitialized(ServletContextEvent e) {
- LifecycleFactory factory = (LifecycleFactory)
- FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
-
- Lifecycle lifecycle = factory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
-
- lifecycle.setApplicationHandler(new SimpleApplicationHandler());
- }
- public void contextDestroyed(ServletContextEvent e) {
- // Nothing to do here
- }
- }
Servlet containers create servlet context listeners at application startup and invoke the listener's contextInitialized() method. When the application shuts down, the servlet container invokes the listener's contextDestroyed() method. The servlet context listener listed above creates an application handler and associates it with the JSF lifecycle. Application handlers handle application events and specify a URL that the JSF implementation subsequently forwards to, as illustrated by the application handler created in Example 2 and listed in Example 3.
servlet容器在应用启动时生成servlet运行环境监听器并调用监听器的contextInitialized()方法。当应用终止时servlet容器调用监听器的contextDestroyed()方法。上文中的servlet运行环境监听器生成一个应用句柄并把它和运行流程关联。应用句柄处理应用事件并且声明JSF实现后续将要将请求前转的URL,过程在示例2和示例3中说明。
示例3 SimpleApplicationHandler
Example 3. WEB-INF/com/sabreware/appHandlers/SimpleApplicationHandler
- package com.sabreware.appHandlers;
-
- import javax.faces.FactoryFinder;
- import javax.faces.context.FacesContext;
- import javax.faces.event.FacesEvent;
- import javax.faces.lifecycle.ApplicationHandler;
- import javax.faces.tree.TreeFactory;
-
- public class SimpleApplicationHandler implements ApplicationHandler {
- public boolean processEvent(FacesContext context, FacesEvent facesEvent) {
- TreeFactory treeFactory = (TreeFactory)FactoryFinder.
- getFactory(FactoryFinder.TREE_FACTORY);
- context.setResponseTree(
- treeFactory.getTree(context.getServletContext(),
- "/welcome.jsp"));
- return true;
- }
- }
In the JSF lifecycle's Render Response phase, the JSF implementation forwards to a URL. That URL represents a component tree, which is known as the response tree. The application handler listed above sets the response tree to /welcome.jsp, and the JSF implementation subsequently forwards to that URL after the application handler is invoked (in the Invoke Application phase of the JSF lifecycle). Our simple example only generates one application event—a form event generated when the Log In button is activated. JSF applications can generate two types of application events: form events and command events. Command events are generated when you click on a link.
在JSF处理流程中的响应合成阶段,JSF实现将请求前转到一个URL中。这个URL创建一个叫做响应树的组件树。上文的应用句柄将这个响应树赋予/welcome.jsp,在应用句柄被激活(在调用Web应用阶段)以后JSF实现紧接着前转到这个URL。我们的这个简单的应用仅生成一个应用事件——当Log In按钮被按下时触发的表单事件。JSF应用可以生成两种类型的应用事件:表单事件和命令事件。命令事件通过点击链接生成。
The servlet context listener listed in Example 2 and the application handler listed in Example 3 work hand in hand. The context listener creates the application handler, and the application handler specifies a URL that the JSF implementation forwards to when the login form is submitted.
示例2中的servlet运行环境监听器和示例3中的应用句柄协同工作。运行环境监听器生
成应用句柄,而应用句柄声明了当login表单提交时JSF实现所应当前转的URL。
The welcome file, /index.html, is listed in Example 4.
示例4 欢迎文件,/index.html
Example 4. /index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<font size='4'>Welcome to a simple JavaServer Faces Application</font>
<p>
<a href='faces/index.jsp'>Click here to start the application</a>
<body>
</html>
The welcome file listed above creates a link to the first JSP page displayed by the application. All JSF applications must route the first JSP page displayed by the application through the JSF controller servlet. You can either provide an HTML page that contains a link to that JSP page, as illustrated in this example, or you can rely on the user to type the correct URL to start the application. Unfortunately, neither solution is very appealing; hopefully, JSF 1.0 will provide a mechanism to obviate this requirement.
上文的欢迎文件包含一个指向这个JSF应用显示的第一个JSP页面的链接。所有的JSF应都必须通过JSF控制器导向到各自应用所显示的第一个JSP页面。你可以象示例一样提供一个包含指向这个JSP页面的链接的HTML页面,或者让用户直接输入正确的URL地址以便激活应用。不幸的是,它们都不是很方便;希望在JSF 1.0版本中能提供满足这个需求的机制。
The application's initial JSP page is listed in Example 5.
示例 5 应用的初始JSP页面
Example 5. /index.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri="http://java.sun.com/j2ee/html_basic/" prefix="faces" %>
<font size="4">Please enter your name and password</font>
<faces:usefaces>
<faces:form id="simpleForm" formName="simpleForm">
<table>
<tr>
<td>Name:</td>
<td><faces:textentry_input id="name"/></td>
</tr>
<tr>
<td>Password:</td>
<td><faces:textentry_secret id="password"/></td>
</tr>
</table>
<p><faces:command_button id="submit" commandName="Log In"/>
</faces:form>
</faces:usefaces>
</body>
</html>
The preceding JSP page is where most of the action takes place in our simple application. JSF provides JSP tags for all of the standard components that JSF supports. Those tags must be contained within the body of a <faces:usefaces> tag. The JSP page listed above uses the <faces:form> tag, which creates an HTML form, and the <faces:textentry_input> and <faces:textentry_secret> tags, which render an HTML text element and an HTML password element, respectively. The JSP page also uses the <faces:command_button> tag, which renders an HTML Submit button.
前面的这个JSP页面包含了我们这个简单的应用中大多数的动作。JSF提供了所有JSF支持的标准的组件的JSP 标签。这些tags都必须包含在一个<faces:usefaces>标签所标记的块中。上面的页面通过<faces:form>标签生成一个HTML的表单,<faces:texentry_input> 标签和<faces:textentry_secret>标签分别生成一个HTML的文本输入框和密码输入框。同样通过<faces:command_button>标签提供一个HTML的提交按钮。
When the form in the preceding JSP page is submitted, the JSF lifecycle begins, and the application handler subsequently invokes. That handler specifies /welcome.jsp as the response tree, and the JSF implementation subsequently forwards to that JSP page, which is listed in Example 6.
当前面这个JSP页面中的表单被提交时,JSF的处理流程开始了,应用句柄被调用。这个应用句柄声明/welcome.jsp作为响应树,并且JSF实现随之将请求前转到这个JSP页面中,示例 6说明了这个处理过程。
示例6 /welcome.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
Welcome to JavaServer Faces!
</body>
</html>
Now that we've seen how a simple JSF application works, let's extend that application by adding field validation.
现在我们已经看到了一个简单的JSF应用是如何工作的,下面让我们扩展一下加入字段的验证。
用JSF进行验证
JavaServer Faces provides built-in validation and a framework for creating custom validators. Built-in validation is discussed below; custom validation will be discussed in Part 2.
JSF提供了内建的验证和创建定制的验证的框架。我们首先讨论内建的验证,定制的验证将在第二部分讨论。
内建的验证(Built-in validation)
JavaServer Faces provides the following built-in validators:
JSF提供了以下内建的验证器:
DoubleRangeValidator
LengthValidator
LongRangeValidator
RequiredValidator
StringRangeValidator
The preceding list of validators represent class names. Those classes reside in the javax.faces.validator package. The DoubleRangeValidator and LongRangeValidator validate that a request parameter (which is always a string) can convert to either a double or long, respectively, and that those values fall within a specified range. The LengthValidator checks the string length of a request parameter against minimum or maximum values. The RequiredValidator requires a non-null value for a given field. The StringRangeValidator converts a string into either a long or a double and checks that value against specified minimum or maximum values.
前面罗列的是验证器的类名。这些类都在javax.faces.validator包中。DoubleRangeValidator 和LongRangeValidator验证一个请求参数是否可以转换成为一个双精度浮点数或长整数 并且在某个指定的范围内。LengthValidator验证阐述的长度是否在指定的最小和最大值之间。RequiredValidator检验必须提供的字段是否有非空的数值。StringRangeValidator将一个字符串转换为长整数或者双精度浮点数同时验证是否在指定的最小和最大值之间。
图 3 JSF内建的验证器
Figure 3 shows an error message generated by a length validator. The minimum length was specified as three, but the value entered in the corresponding field was only two characters, so a validation error and corresponding error message were generated when the field's corresponding form was submitted.
图3显示了长度验证器生成的错误信息。最短长度声明为3,但是输入的数据的长度为2,所以当该页面提交的时候出现一个验证错误同时生成了错误信息。
Example 7 lists the JSP page shown in Figure 3.
示例 7 图 3中的JSP页面。
示例 7. 使用长度验证器(Use the LengthValidator)
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri='http://java.sun.com/j2ee/html_basic/' prefix='faces' %>
<font size='4'>Please enter your name and password</font>
<faces:usefaces>
<faces:form id='simpleForm' formName='simpleForm'>
<table>
<tr>
<td>Name:</td>
<td>
<faces:textentry_input id='name'>
<faces:validator
className='javax.faces.validator.LengthValidator'/>
<faces:attributename=
'javax.faces.validator.LengthValidator.MINIMUM'
value='3'/>
</faces:textentry_input>
</td>
<td>
<faces:validation_message componentId='name'/>
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<faces:textentry_secret id='password'/>
</td>
</tr>
</table>
<p><faces:command_button id='submit' commandName='Log In'/>
</faces:form>
</faces:usefaces>
</body>
</html>
As evidenced by the preceding JSP page, JSF validators are easy to use: simply add a <faces:validator> tag and one or more <faces:attribute> tags to the body of the component you want to validate. Validators store error
messages in the JSF context when validation fails; you can extract those error messages with the <faces:validation_message>, which lets you specify the component to which those messages apply.
就像前面的JSP页面所说明的,JSF的验证器是非常易于使用的:简单的添加一个<faces:validator>标签和一个或几个<faces:attribute>标签到你希望进行验证的组件中。当验证失败的时候,验证器会将错误信息存储于JSF的运行环境中;你可以使用<faces:validation_message>解析这些信息,它是用于标识具体哪个组件将使用这些信息的。
仍有更多(More to come)
JSF represents a new paradigm for developing J2EE applications.With a well-defined request processing lifecycle, event handling, validation, and a rich component hierarchy for developing complex custom components that can write to multiple devices, JSF will greatly facilitate the development of J2EE application Web tiers.
JSF提出了一种新的开发J2EE应用的框架。通过良好定义的请求处理流程、事件处理、验证机制和可以用于多种设备的用于开发复杂的定制组件的丰富的组件库,JSF将极大的推动基于Web的多层的J2EE应用的开发。
In this article, I introduced basic JavaServer Faces concepts, including the JSF lifecycle, using JSF standard components and their corresponding JSP tags, and built-in validation. In Part 2, I will discuss more advanced JSF features, including custom validation, internationalization, using model objects, and implementing custom components.
通过本文,我介绍了基本的JSF概念,包括JSF处理流程、使用JSF标准组件和对应的标签和内建的验证机制。在第二部分中,我将讨论更多的JSF高级特性,包括定制验证、国际化支持、使用模型对象和实现定制组件。
About the author
David Geary is the author of Core JSTL Mastering the JSP Standard Tag Library (Prentice Hall, 2002; ISBN: 0131001531); Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041); and the Graphic Java series (Sun Microsystems Press). David has been developing object-oriented software with numerous object-oriented languages for 18 years. Since the GOF Design Patterns book was published in 1994, David has been an active proponent of design patterns and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert group defining the JSP Standard Tag Library, and is a contributor to the Apache Struts JSP framework. He writes JavaWorld's Java Design Patterns column.
Resources
• Download the source code that accompanies this article:
http://www.javaworld.com/jw-11-2002/jsf/jw-1129-jsf.jar • An integration strategy for Struts and JavaServer Faces:
http://www.mail-archive.com/struts-dev@jakarta.apache.org/msg08457.html • Download the JSF specification, the reference implementation, two sample applications, and a JSF tutorial from:
http://java.sun.com/j2ee/javaserverfaces • Browse the JavaServer Pages section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-jsp-index.shtml • Browse the Enterprise Java section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-enterprise-index.shtml • David Geary's Java Design Patterns column in JavaWorld:
http://www.javaworld.com/columns/jw-java-design-patterns-index.shtml • Visit JavaWorld's Enterprise Java discussion:
http://forums.devworld.com/webx?50@@.ee6b80a • Sign up for JavaWorld's free weekly Enterprise Java email newsletter:
http://www.javaworld.com/subscribe • You'll find a wealth of IT-related articles from our sister publications at
IDG.net
Summary In September 2002, the early access (EA) draft of the JavaServer Faces specification was released under Java Specification Request (JSR) 127. JavaServer Faces, with a well-defined request processing lifecycle and a rich component hierarchy, will profoundly affect the development of Java 2 Platform, Enterprise Edition (J2EE) applications. In Part 1 of this two-part series, David Geary introduces JavaServer Faces and explores its fundamental concepts. (3,000 words; November 29, 2002)
摘要:在2002年9月的127次JSR会议上发表了JavaServer Faces规范的早期草稿版本。具有良好定义的请求处理生命周期和丰富的组件层次结构的JSR将会深远的影响到J2EE应用的开发。在本篇分为两部分的文稿的第一部分中,David Geary将介绍JSR并初步探讨它的基本概念。
Recently, I had the good fortune of training and mentoring a group of novice Java developers as we implemented a complex Web application using Struts, Enterprise JavaBeans (EJB), servlets, JavaServer Pages (JSP), and the JSP Standard Tag Library (JSTL). As it turned out, the project was a success; it came in under budget and on time, and had numerous features not originally envisioned. As you might imagine, we faced many technical challenges along the way; the most significant were:
最近,我在使用Struts、EJB、JSP和JSTL开发一个复杂的Web应用的过程中能有幸培训和指导一组共同参与开发的初级Java开发人员。当开发完成以后,整个项目非常成功并且是在经费预算和进度规划内完成的,而且实现了很多原先没有设想到的功能特性。当然我们在开发的过程中也遇到了相当多的技术挑战,最典型的有:
1. Implementing custom components, Which included a tree/table viewer and a query builder that lets users dynamically add and remove fundamental components such as text fields and drop-down lists used to build database queries.
1. 实现客户端组件,诸如树型、列表的视图和允许用户在创建数据库查询时动态的增加和删除类似于文本输入框或者下拉列表等基本元素的查询构造器的客户端组件。
2. Supporting hand-held devices, such as PDAs and radio frequency devices.
2. 支持手持设备,例如PDA和射频设备。
3. Lack of an IDE for effective rapid application development (RAD).
3. 缺乏有效的能够支持快速应用开发的集成环境。
Implementing custom components and supporting hand-held devices—especially the latter—consumed a great deal of our time and effort. Also, although some of the developers used the Eclipse open source IDE, we lacked an effective RAD tool for implementing the Web application's user interface.
实现客户端组件和支持手持设备消耗了大量的时间精力。尽管一部分开发人员使用了开 放源码的Eclipse基层开发环境,但是我们在Web应用的客户界面开发方面还是没有有效的RAD工具。
Unless you've been living in a cave for the past few years, I'm sure you're aware that tools exist for creating custom Web components and supporting markup languages other than HTML, all of which are wrapped up in a very nice IDE. That software, of course, is Microsoft's .Net with WebForms; the IDE is Visual Studio.
我确信除非你不韵世事,否则你肯定知道用于开发用户Web组件和支持HTML以外的标记语言的工具已经被集成到了一个非常不错的开发工具中了。当然这个工具就是Microsoft's .Net with WebForms,而这个开发环境就是Visual Studio。
In spite of those attractive .Net features, the company I was working
for—like many software development companies nowadays—opted to go with the Java 2 Platform, Enterprise Edition (J2EE) because of its platform and
vendor independence and the wealth of available open source software for Java and J2EE.
尽管.NET具有很多引人瞩目的特性,我所工作的公司和目前的许多软件开发公司一样,因为J2EE的平台无关性和大量可以利用的开放源码的软件而倾向于在J2EE上进行开发
Wouldn't it be nice if you could take advantage of Java and .Net's best features, platform and vendor independence, open source products such as Ant and log4j, and the ability to easily create custom Web components and render them to multiple devices, all wrapped up in a killer IDE? That's the promise of JavaServer Faces.
如果我们能把所有这些Java和.NET各自的优点,平台无关的特性,类似Ant和Log4j这样优秀的开放源码的软件产品以及能够简便的生成客户Web组件并发布到多种设备上的能力组合到一个独一无二的集成开发环境中,那这个开发环境将是非常的优秀啊?这就是 JSF将提供给我们的东西。
JSF是什么?
JavaServer Faces (JSF) is an application framework for creating Web-based user interfaces. If you are familiar with Struts (a popular open source JSP-based Web application framework) and Swing (the standard Java user interface framework for desktop applications), think of JavaServer Faces as a combination of those two frameworks. Like Struts, JSF provides Web application lifecycle management through a controller servlet; and like Swing, JSF provides a rich component model complete with event handling and component rendering.
JSR是生成基于Web的用户界面的应用程序框架。如果你对Struts(流行的开放源码的Web应用程序框架)和Swing(标准的用于桌面应用的Java用户界面框架)都很熟悉的话,可以认为JSF是他们二者的集成。类似于Struts,JSF通过一个控制器Servlet提供了Web应用的生命周期管理;同时类似于Swing,JSF提供了包括事件处理和组件生成在内的丰富的组件模型。
In a nutshell, JSF eases Web-based application development because it:
Lets you create user interfaces from a set of standard, reusable server-side components Provides a set of JSP tags to access those components Transparently saves state information and repopulates forms when they redisplay Provides a framework for implementing custom components Encapsulates event handling and component rendering so you can use standard JSF components or custom components to support markup languages other than HTML Lets tool vendors develop IDEs for a standard Web application framework
简单的说,JSF基于以下的原因简化了基于Web的应用的开发:
◆使你能够利用一些标准的可重用的服务器端组件来创建客户界面。
◆提供了一组JSP 标签来获取(访问)这些组件。
◆开发人员不用关心当页面刷新的时候页面状态数据的存储和重现。
◆提供了一个用于实现定制组件的框架
◆封装了事件处理和组件显示,所以你可以使用标准的或者定制的JSF组件支持HTML以外的标记语言。
◆开发工具提供商可以开发针对标准Web应用框架的集成环境。
Besides being a conceptual combination of Struts and Swing, JSF is a direct competitor to Microsoft's WebForms. The frameworks are very similar, both in concept and implementation. And because JSF represents a standard for Java-based Web application frameworks, tool vendors can concentrate on developing IDEs for JSF instead of developing an IDE for one of approximately 35 existing Java-based Web application frameworks, including Struts.
除了作为Struts和Swing概念上的统一体外,JSF还将成为Microsoft的WebForms的直接 竞争对手。这两种框架不论从概念或者实现上都非常相似。由于JSF作为基于Java的Web 应用框架的标准,工具开发商们可以专注于为JSF开发集成环境,而不仅仅为包括Struts在内的大约35种基于Java的Web应用框架的其中之一开发集成环境。
Note: Struts developers needn't worry; although JSF and Struts have much in common, JSF will not make Struts obsolete. See Resources for a discussion of an integration strategy for Struts and JavaServer Faces.
注:Struts开发人员不用担忧;尽管JSF和Struts很相像,但JSF并不会放弃Struts。在参考资料中有关于集成两者的讨论。
Currently, JSF is an early access (EA) release, and, as a result, is somewhat immature. The specification leaves some functionality unspecified, and the specification and reference implementation are currently out of sync, with the former specifying new syntaxes and functionality not yet implemented in the latter. On the other hand, JSF is mature enough for you to write code against—although much of that code is guaranteed to be obsolete (see the disclaimer below)—and the reference implementation is fairly complete and relatively bug-free. You can download the JSF specification, the reference implementation, two sample applications, and a JSF tutorial from Resources.
目前JSF还仅仅是EA版本,所以不是很成熟。规范当中还有很多功能没有阐述,规范和 参考实现也不同步,规范中描述的语法和功能还没有得到实现。另一方面,JSF已经足够成熟得让你根据它进行编程——尽管有些代码将会被废弃(参看下文声明)——而且参考实现已经基本完成而且比较可靠。你可以从参考资源中下载JSF的规范、参考实现、两个样例应用和一份JSF教程。
The two articles in this series provide a code-intensive introduction to JavaServer Faces. In this article, I begin with a short discussion of the JSF lifecycle and then dive into some example code that illustrates implementation of Web-based user interfaces with JSF and how you can take advantage of built-in validation. In Part 2, I will explain more advanced JSF concepts such as: implementing custom validation; using model objects; internationalization; creating custom components; and finally, delegating event handling and rendering so you can use components to generate markup languages other than HTML.
本系列的两篇文章提供的是并不偏重编码的JSF介绍。在本篇中,我在简短的介绍了JSF的生命周期以后将通过一些示例代码来说明如何通过JSF来实现基于Web的用户界面以及如何利用内建的验证功能。下一篇中,我将阐述一些JSF的高级概念:实现定制验证、使用模型对象、国际化支持、生成定制组件和便于你使用组件生成HTML以外的标记语言的事件的代理和处理机制。
Disclaimer: The code discussed in this article was written against the EA2 JSF reference implementation. As mentioned above, the specification and reference implementation are in a state of flux, and therefore, the code in this article is guaranteed to be obsolete in the near future; however, the code works as advertised with the EA2 reference implementation and was tested with both Tomcat 4.0.6 (the latest production release of Tomcat) and Resin 2.1.6. Furthermore, you can read the JSF specification until the cows come home, but to really grasp the concepts, you must ruminate over some code.
声明:本文中的代码均针对EA2版本的JSF参考实现编写。前面已经说明,规范和参考实现目前还在修订当中,这些代码将很快会被废弃;然而这些代码可以在EA2版本的参考实现上运行,并且在Tomcat 4.0.6和Resin 2.1.6上通过了测试。当然你也可以研读规范直至领会,但是如果你想真正掌握概念,就应该做一些深入的编码实践。
JSF的运行周期(The JavaServer Faces lifecycle)
JSF handles HTTP requests with seven distinct phases, as shown in Figure 1. The normal flow of control is shown with solid lines, whereas dashed lines show alternate flows depending on whether a component requests a page redisplay or validation or conversion errors occur.
JSF通过7个步骤来处理一个HTTP请求,如图1。正常的处理流程通过实线标识,虚线表示一些诸如刷新显示、验证错误、转换错误等特殊情况的可选的处理流程。
The Reconstitute Request Tree phase creates a component tree for the requested page. If that page previously displayed and JSF saved the page's state information, the state information is added to the request. This means that JSF automatically retains form information when a form redisplays; for example, when a user does not correctly fill out a form. This handy feature is a fundamental capability provided by Microsoft's WebForms, but is otherwise absent from J2EE.
重建请求树阶段为被请求的页面创建组件树。如果这个页面曾经被访问过,JSF会保存 上次访问时的状态信息和数据,在此时将这些状态数据加入到当前的请求。这意味着当重复访问某个表单的时候JSF将自动的恢复表单数据。这个便利的功能在Microsoft的WebForms中是基本功能,但是在J2EE中则被遗漏了。
During the Apply Request Values phase, the JSF implementation iterates over the components in the component tree and calls each component's decode() method. That method extracts information from the request and stores it in the component. Optionally, components may delegate decoding to a renderer.
在请求数据解析阶段中,JSF实现遍历组件树中所有的组件调用所有组件的decode()方 法。decode()方法将从请求中提取信息并存储到组件当中。某些情况下,组件可用于为响应合成器提取数据。
In addition to decoding request information during the Apply Request Values phase, components or their renderers may create request events. Typically, request events signal a visual change for one or more components; for example, clicking on a graphic in a tree control may expand a branch of the tree. Alternatively, an event in one component may update the visual representation of another component; for example, clicking on a leaf node in a tree may cause an associated list to change its contents and redisplay. In either situation, a request event is generated and added to the JSF context.
另外在请求数据解析阶段提取请求信息的过程中,组件或者他们的响应合成器可能会生成一些请求事件。最典型的有请求事件可能会触发了一个或多个组件的显示变化;例如当点击一个树型控件可能会展开它的分支。另外,某个组件的事件可能会更新另一个组件的显示;例如当点击一个树型控件的叶节点可能会导致和它关联的列表控件改变它的内容和显示。在任何一种情况下,都会产生一个请求事件加入到JSF的运行环境中。
Request events, which are generated during the Apply Request Values phase, are handled during the Handle Request Events phase. During the Handle Request Events phase, the JSF implementation calls the processEvents() method for each component that has one or more request events. Components may handle request events themselves, or they may choose to delegate event handling to an event handler. The processEvents() method is a boolean() method. If that method returns false, lifecycle processing advances to the Process Validations phase; otherwise, lifecycle processing advances directly to the Render Response phase.
请求数据解析阶段产生的请求事件都在请求事件处理阶段处理。在请求事件处理阶段JSF实现为那些有一个或多个请求事件的组件调用processEvents()方法。这些组件将自行处理这些事件或者提交给某个事件处理器代理处理。processEvents()方法返回值为boolean。如果返回false,处理周期将前进到验证处理阶段,否则将直接跳转至响应合成阶段。
During the Reconstitute Request Tree phase, the JSF implementation may register one or more validators for any of the components in the component tree. In the Process Validations phase, the JSF implementation invokes the validate() method for each validator. Validators perform correctness checks and return a boolean value from their validate() method; if that method returns true, the JSF lifecycle proceeds normally; otherwise, the JSF implementation invokes the Render Response phase directly.
在重建请求树阶段,JSF实现会为请求树上的组件注册一个或多个验证器。在验证处理阶段,JSF实现调用每一个验证器的validate()方法。验证器执行validate()方法进行正确性检验以后返回一个boolean值;如果为true,JSF处理周期将继续前进;否则将直接跳转至响应合成阶段。
Each JSF user interface component can be associated with a field in a Java object (known as a model object). During the Update Model phase, component values are copied to the component's model object. A component's updateModel() method carries out that data transfer. Conversion errors can occur during this phase because request parameters are strings, but model values can represent any type of Java object. If a conversion error occurs, the JSF implementation invokes the Render Response phase directly.
每一个JSF用户界面组件都关联于一个Java对象(被称为模型对象)的某个字段。在模型更新阶段,组件的值将被复制到对应的组件当中。数据传递通过模型对象的updateModel()方法调用完成。由于请求参数都是字符串而模型对象字段有可能是任何Java对象类型,如果发生转换错误,JSF实现将直接跳转至响应合成阶段。
In a JSF application, if you submit a form or click on a link (both of which must be represented by JSF components), the JSF implementation creates a form event or a command event, respectively. Those events are handled in the Invoke Application phase by an application-specific handler. Typically, those handlers specify a URL, and the JSF implementation forwards the request to that URL. Currently, application-specific handlers handle form and command events in a single method, typically with a switch statement. The JSF expert group is aware of this approach's ugliness, and therefore, it's almost certain to change in the JavaServer Faces 1.0 release.
在JSF应用中,如果你通过提交一个表单或者点击一个连接(都需要是通过JSF组件提供的),JSF实现将分别生成一个表单事件和命令事件。这些事件将在调用Web应用阶段由一个应用声明的处理器进行处理。典型的情况是处理器声明了一个URL,JSF实现将这个请求前转到这个URL中。目前应用声明的处理器对此的处理都是通过一个包含一个switch语句的单一方法进行的。JSF专家组意识到这样的方案不是很合理,因此在JSF 1.0的正式发行版将肯定会有所改变。
Finally, the Render Response phase creates a response component tree and forwards the response. When a user submits a form, clicks on a link, or otherwise generates a request, the cycle starts anew.
最后,响应合成阶段生成一个响应组件树并发送响应。当用户再次提交一个表单或点击一个链接,总之生成一个请求,那么处理流程将重新开始。
Now that we have a general overview of JavaServer Faces and a rudimentary understanding of the JSF lifecycle, let's take a look at some code.
现在我们已经对JSF和处理流程有了一个粗略的认识,下面将研究一些代码。
Seegeris,Bruce
上周在Colorado,Martin Fowler 和 Bruce Eckel 邀请了一些“大腕”级的人物,如Rod Johnson,Floyd Marinescu等,开了一个“座谈会”(现场的一些照片在这里)。 其中讨论到:“企业级架构最关键的原则问题是什么”。 这些“大腕”一共总结出来40条,然后投票得出了最关键的5条 (Top 5 Principles of Enterprise Architecture):
- Use a layered architecture.
- Build Automated Regression Tests, which was tied with:
- Manage your application as you would a software product. eg: frequent and numbered releases, same rigor as a product.
- Use the smallest team you possibly can tied with:
- Attack the domain problem first (or - work on your domain model before other parts of the app).
与之对应的Top Bottom 5则是(从后往前):
- Use Model Driven Architecture.
- Determine all your requirements upfront.
and a three way tie between: (最后3个并列)
- Use EJBs.
- Prefer web based UI's.
- Prefer open source projects.
Floyd Marinescu关于这次“研讨会”更详细的blog。
大家在使用Google的时候除了使用他的主页面的搜索引擎的功能之外,还有没有尝试过其他的功能呢?可能大家会觉得奇怪,除了搜索引擎,Google还有其他的功能吗?其实Google的功能远远比我们想象的要大得多,我们平时使用的功能也许只占其中的30%不到。下面我就给大家介绍一下Google其他的更为强大却鲜为人知的功能吧。(只要Google有新的服务,我就会发在这后面)1·在线翻译服务 在你查询英文网页的时候,你会发现,旁边多出了一个“翻译此页 Beta”的连接,如果我们点击这个连接,Google就能将翻译好的网页呈现给你。
下面做一个例子,在上一个随笔中我写到了http://www.fluxiontech.com,上面有很多GTalk新鲜功能的介绍,我没有时间将他的内容翻译,那么这时候Google的在线翻译功能就有用了。
我们只需要在浏览器地址栏输入:http://translate.google.com/translate?hl=zh-CN&sl=en&u=http://www.fluxiontech.com,看,是不是翻译成中文了,而且翻译的效果还是可以的,如果不信大家可以试试用那些收费的软件翻译一下,结果不会比这个好。我自己试过用金山快译,效果还不如Google的翻译。
其实原因还是比较简单的,因为Google翻译的翻译数据库是他背后如此海量的搜索数据,10多亿的网页里面的内容啊!就像一个见多识广的人,无论如何翻译起文章来也比那些只有几十或者几百兆数据库的翻译软件强的。
那么如果我们要让中文翻译成英文呢?就拿我这个网页来做个例子吧。我的网页的地址是:
http://www.blogjava.net/chenpengyi/archive/2005/08/27/11265.html
翻译后的结果是:http://translate.google.com/translate?langpair=zh-CN&hl=en&u=http://www.blogjava.net/chenpengyi/archive/2005/08/27/11265.html
让人诧异的功能吧!!
仔细观察不难发现,这些语句中处理翻译选项和翻译网址的语句是hl=fr&sl=en&u=,很简单(这里的hl可以换成langpair)。我们很容易可以看出,hl的等号后面指代的是你需要翻译成为的语言(例子中的zh-CN,简体中文),而sl后面则是(应该是source language的意思)你需要翻译的源文件的语言(例子中的是en,英文),那么我们就可以随意调换,获得自己想要的效果。
我暂时还不知道如何调用她来翻译本机的文件,但是可以间接通过其他方式实现这样的效果的。我们可以申请一个类似博客的网记,然后把自己的文章往上贴,假设我们贴好的文章的地址是http://www.chenpengyi.com/abc.html ,
如果要把英文翻译成中文则在地址栏输入:
http://translate.google.com/translate?hl=zh-CN&sl=en&u=+http://www.chenpengyi.com/abc.html (你文档所在的网页)
也就是http://translate.google.com/translate?hl=zh-CN&sl=en&u=http://www.chenpengyi.com/abc.html
如果是中文翻译英文则输入:
http://translate.google.com/translate?langpair=zh-CN&hl=en&u=+http://www.chenpengyi.com/abc.html (你文档所在的网页)
也就是http://translate.google.com/translate?langpair=zh-CN&hl=en&u=http://www.chenpengyi.com/abc.html
那么这里支持的语言是中文和英文,其实Google支持的翻译的语种还有很多的,只要大家知道了相应的代码就可以很方便的使用了。下面我把我所知道的一些Google内部所支持的翻译语言的国家代码公布一下,不过Google支持的远不止那么少了,这里只是一部分:
简体中文(zh-CN) 繁体中文(zh-TW) 英语(en) 德语(de) 日语(ja) 俄语(ru)
意大利语(it) 拉丁文(la) 印度(hi) 印尼(id) 希腊(el) 泰国(th)
土耳其(tr) 挪威(no)等等
那么大家只要把sl和hl所对应的语言换成上面的语言代码就可以完成翻译了,多方便,呵呵,应该多外国语学校学校非英语语种的同学最有用了,这样一来看资料速度快多了。
相信这么详细的介绍大家应该知道怎么使用Google的在线服务了吧?如果你有什么心得也可以给我发邮件(chenpengyi#gmail.com )讨论,如果转载请注明出处http://www.blogjava.net/chenpengyi,谢谢。
最新发现!其实Google的在线翻译可以自定义想翻译的内容的,提供输入框,和翻译语言的选项,那我们就不需要那么麻烦把资料发到网上了。
她的地址是:http://www.google.com/language_tools?hl=zh-CN
BTW:这里还有特定语言搜索功能和好多国家的国旗,哈哈
2·Google学术论文搜索
相信各位在写论文的时候总会遇到论文内容不够,但是在万方或者超星却难找到相应的资料,因为那些数据库中国外的资料太少了,即使有也是n年前的了。遇到这样的情况总会郁闷很久,最后只好随便写了些内容凑数。其实大家不知道,Google很早就有专门的论文搜索数据库了,只是没有公开而已,我们可以通过下面的网址访问:
http://scholar.google.com/
相信在这里你可以找到你需要的文章,绝对多!
3·Google 大学搜索
如果想在某个大学内部找一些资料,而又不想与网络其他的资料混淆怎么办呢?我们可以通过Google特定的大学搜索来实现,这个搜索不是我们以前知道的在搜索资料后打入site:【www.chenpengyi.com(你需要搜索的网站)】命令,而是专门为大学内部搜索定制的一个搜索引擎,功能也是很强大的。
http://www.google.com/intl/zh-CN/options/universities.html
大家如果想在某个大学的bbs或者是网页上找某些信息完全可以通过这里找,比在传统搜索引擎上大海捞针快多了,也准确多了。大家可以试试,比较有特色的功能,符合Google一贯的作风,实在,技术。
4·Google 其他实用小功能
除了上面以外,其实Google也提供了很多实用的小功能,如:
1 •查找Flash 文件 Doc、PDF、PPT等特定常用类型的文件
2 •网页快照 提供网页信息
3 • 货币转换
4• 计算器
5• 相关搜索
6• 类似网页
7• 按链接搜索
8• 指定网域
9• 手气不错
10• 错别字改正
11• 中英文字典
12• 天气查询
13• 股票查询
14• 邮编区号
15• 手机号码
16• 自定义
具体的解释不多说了,大家自己试试就知道了,反正比较不错。
5·Google 地图服务
Google的地图服务也就是大家之前说的那个引起国防部重视的卫星地图服务。可以清楚的看到道路上的人的卫星地图,我用过了,确实有这样的效果,但是地图是3年前的。如果有兴趣可以去看看:
http://maps.google.com/
总体来说还是比较不错的,提供两种选择,卫星地图和电子地图。推荐电子地图,因为这个的信息很齐全,可以搜索周围的商店和建筑。感觉和Google的Froogle服务有合作的倾向。
6·Google 网页加速器
Google Web Accelerator是比较不错的网络插件,算法比较好,我这里有个网页是介绍它加速原理的,大家可以去看看http://www.wespoke.com/archives/000957.html,界面如下:
大家自己去试试,据说针对ASDL和有线宽频等优化过,提速效果很好。
7·Google影视搜索服务(video search)。
这个功能我觉得对我没有太大的用处,就不知道对大家有没有用了。如果你想找到一些电视节目的话,可以来这里找找看的,这个找全世界电视节目的功能还是蛮强的。其他评论就不多说了,大家自己试用。
http://video.google.com/
8·用Google 搜索资料技巧
如果掌握了Google搜索的技巧可以搜索到一些你根本意想不到的东西:
在搜索框上输入:
"index of/ " inurl:lib
再按搜索你将进入许多图书馆,并且一定能下载自己喜欢的书籍。
在搜索框上输入: index of /" cnki
你就可以找到许多图书馆的CNKI、VIP、超星等入口!
在搜索框上输入: "index of /" 要下载的软件名
可以突破网站入口下载软件!
这是看别人的资料后提取了重要的部分,具体这个"index of /"是什么也没去研究了。如果有人知道请告诉我,谢谢。
如果要在一个站点内找你需要的东西,只需要输入:
关键字+site:www.chenpengyi.com 这里
www.chenpengyi.com是你需要找东西的网站。
还有很多这样的命令,如inurl: ,intitle:等我会陆续贴上来。
8·Google 还有很多服务,今天暂时放那么多了,希望大家喜欢。
原创,如果需要转载,请注明来源
http://www.blogjava.net/chenpengyi和作者:陈朋奕。
探查内存不足/内存泄漏问题 |
|
问题描述
内存不足 (OOM) - 由于 java 堆或本地内存中的内存耗尽,应用程序显示“内存不足”错误。
内存泄漏 - java 堆或本地内存的持续内存增长,最终将导致内存不足状态。调试内存泄漏状态的技术与调试内存不足状态的技术相同。
故障排除 请注意,并非下面所有任务都需要完成。有些问题仅通过执行几项任务就可以解决。
快速链接:
Java 堆、本地内存和进程大小
Java 堆 - 这是 JVM 用来分配 java 对象的内存。java 堆内存的最大值用 java 命令行中的 .Xmx 标志来指定。如果未指定最大的堆大小,那么该极限值由 JVM 根据诸如计算机中的物理内存量和该时刻的可用空闲内存量这类因素来决定。始终建议您指定最大的 java 堆值。 本地内存 - 这是 JVM 用于其内部操作的内存。JVM 将使用的本地内存堆数量取决于生成的代码量、创建的线程、GC 期间用于保存 java 对象信息的内存,以及在代码生成、优化等过程中使用的临时空间。
如果有一个第三方本地模块,那么它也可能使用本地内存。例如,本地 JDBC 驱动程序将分配本地内存。
最大本地内存量受到任何特定操作系统上的虚拟进程大小限制的约束,也受到用 .Xmx 标志指定用于 java 堆的内存量的限制。例如,如果应用程序能分配总计为 3 GB 的内存量,并且最大 java 堆的大小为 1 GB,那么本地内存量的最大值可能在 2 GB 左右。
进程大小 - 进程大小将是 java 堆、本地内存与加载的可执行文件和库所占用内存的总和。在 32 位操作系统上,进程的虚拟地址空间最大可达到 4 GB。从这 4 GB 内存中,操作系统内核为自己保留一部分内存(通常为 1 - 2 GB)。剩余内存可用于应用程序。
Windows缺省情况下,2 GB 可用于应用程序,剩余 2 GB 保留供内核使用。但是,在 Windows 的一些变化版本中,有一个 /3GB 开关可用于改变该分配比率,使应用程序能够获得 3 GB。有关 /3GB 开关的详细信息,可以在以下网址中找到: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ddtools/hh/ddtools/bootini_1fcj.asp
RH Linux AS 2.1 - 3 GB 可用于应用程序。
对于其它操作系统,请参考操作系统文档了解有关配置。
返回页首
进程地址空间和物理内存之间的差异
每个进程都获得其自有的地址空间。在 32 位操作系统中,此地址空间范围为 0 到 4 GB。此范围与计算机的可用随机存取内存 (RAM) 或交换空间无关。计算机中的可用物理内存总量是该计算机上的可用 RAM 和交换空间之和。所有运行的进程共享这些物理内存。
进程内的存储地址是虚拟地址。内核将此虚拟地址映射到物理地址上。物理地址指向物理内存中的某个位置。在任一给定时间,计算机中运行进程所使用的全部虚拟内存的总和不能超过该计算机上可用物理内存的总量。
返回页首
为什么会发生 OOM 问题,JVM 在这种情况下如何处理?
java 堆中的内存不足 如果 JVM 不能在 java 堆中获得更多内存来分配更多 java 对象,将会抛出 java 内存不足 (java OOM) 错误。如果 java 堆充满了活动对象,并且 JVM 无法再扩展 java 堆,那么它将不能分配更多 java 对象。
在这种情况下,JVM 让应用程序决定在抛出 java.lang.OutOfMemoryError 后该执行什么操作。例如,应用程序可以处理此错误,并决定以安全方式自行关闭或决定忽略此错误。如果应用程序不处理此错误,那么抛出此错误的线程将退出(如果您进行 java Thread Dump,那么将看不到该线程)。
在使用 Weblogic Server 的情况下,如果此错误是由某个执行线程抛出的,则会处理此错误并将其记录在日志中。如果连续抛出此错误,那么核心运行状况监视器线程将关闭 Weblogic Server。
本地堆中的内存不足 如果 JVM 无法获得更多本地内存,它将抛出本地内存不足(本地 OOM)错误。当进程到达操作系统的进程大小限值,或者当计算机用完 RAM 和交换空间时,通常会发生这种情况。
当发生这种情况时,JVM 处理本地 OOM 状态,记录说明它已用完本地内存或无法获得内存的消息,然后退出。如果 JVM 或加载的任何其它模块(如 libc 或第三方模块)不处理这个本地 OOM 状态,那么操作系统将给 JVM 发送命令 JVM 退出的 sigabort 信号。通常情况下,JVM 收到 sigabort 信号时将会生成一个核心文件。
返回页首
排除故障的步骤 确定是 Java OOM 还是本地 OOM:
- 如果 stdout/stderr 消息说明这是一个 java.lang.OutOfMemoryError,那么这就是 Java OOM
- 如果 stdout/stderr 消息说明无法获得内存,那么这就是本地 OOM
请注意,上述消息仅发送到 stdout 或 stderr 中,而不发送到应用程序特定的日志文件(如 weblogic.log)
返回页首
对于 Java OOM:
- 收集和分析 verbose gc 输出
- 在 java 命令行中添加“-verbosegc”标志。这样将会把 GC 活动信息打印到 stdout/stderr。将 stdout/stderr 重定向到一个文件。运行应用程序,直到该问题重现。
- 确保 JVM 在抛出 java OOM 之前完成下列任务
完整 GC 运行: 执行一次完整 GC 运行,并且删除了所有不可及对象以及虚可及、弱可及、软可及对象,并回收了那些空间。有关不同级别的对象可及性的详细信息,可以在以下网址中可找到: http://java.sun.com/developer/technicalArticles/ALT/RefObj
您可以检查是否在发出 OOM 消息之前执行了完整 GC 运行。当完成一次完整 GC 运行时,将会打印类似如下消息(格式取决于 JVM - 请查看 JVM 帮助信息以了解有关格式)
[memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms
以上输出的格式如下(备注:在此模式下将全部使用相同的格式):
[memory ] <start>: GC <before>K-><after>K (<heap>K), <total> ms [memory ] <start> - start time of collection (seconds since jvm start) [memory ] <before> - memory used by objects before collection (KB) [memory ] <after> - memory used by objects after collection (KB) [memory ] <heap> - size of heap after collection (KB) [memory ] <total> - total time of collection (milliseconds)
但是,没有办法断定是否使用 verbose 消息删除了软/弱/虚可及的对象。如果您怀疑在抛出 OOM 时这些对象仍然存在,请与 JVM 供应商联系。
如果垃圾回收算法是一种按代回收算法(对于 Jrockit 为 gencopy 或 gencon,对于其它 JDK 则是缺省算法),您也将看到类似如下的 verbose 输出: [memory ] 2.414: Nursery GC 31000K->20760K (75776K), 0.469 ms
以上是 nursery GC(即 young GC)周期,它将把活动对象从 nursery(或 young 空间)提升到 old 空间。这个周期对我们的分析不重要。有关按代回收算法的详细信息,可以在 JVM 文档中找到。
如果在 java OOM 之前未发生 GC 周期,那么这是一个 JVM 错误。
完全压缩: 确保 JVM 执行了适当的压缩工作,并且内存并未成碎片(否则会阻止分配大对象并触发 java OOM 错误)。
Java 对象要求内存是连续的。如果可用空闲内存是一些碎片,那么 JVM 将无法分配大对象,因为它可能无法放入任何可用空闲内存块中。在这种情况下,JVM 将执行一次完全压缩,以便形成更多连续的空闲内存来容纳大对象。
压缩工作包括在 java 堆内存中将对象从一个位置移动到另一个位置,以及更新对这些对象的引用以指向新位置。除非确有必要,否则 JVM 不会压缩所有对象。这是为了减少 GC 周期的暂停时间。
我们可以通过分析 verbose gc 消息来检查 java OOM 是否由碎片引起。如果您看到类似如下的输出(在此无论是否有可用的空闲 java 堆都会抛出 OOM),那么这就是由碎片引起的。
[memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms [memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms [memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms java.lang.OutOfMemoryError
在上述情况中您可以看到,所指定的最大堆内存是 128MB,并且当实际内存使用量仅为 72580K 时,JVM 抛出 OOM。堆使用量仅为 55%。因此在这种情况下,碎片影响是:即使还有 45% 的空闲堆,内存也会抛出 OOM。这是一个 JVM 错误或缺陷。您应当与 JVM 供应商联系。
- 如果 JVM 一切都正常(上一步中提到的所有操作),那么此 java OOM 可能是应用程序的问题。应用程序可能在不断泄漏一些 java 内存,而这可能导致出现上述问题。或者,应用程序使用更多的活动对象,因此它需要更多 java 堆内存。在应用程序中可以检查以下方面:
- 应用程序中的缓存功能 - 如果应用程序在内存中缓存 java 对象,则应确保此缓存并没有不断增大。对缓存中的对象数应有一个限值。我们可以尝试减少此限值,来观察其是否降低 java 堆使用量。
Java 软引用也可用于数据缓存,当 JVM 用完 java 堆时,可以保证删除软可及对象。
- 长期活动对象 - 如果应用程序中有长期活动对象,则可以尝试尽可能减少这些对象的存在期。例如,调整 HTTP 会话超时值将有助于更快地回收空闲会话对象。
- 内存泄漏 - 内存泄漏的一个例子是在应用服务器中使用数据库连接池。当使用连接池时,必须在 finally 块中显式关闭 JDBC 语句和结果集对象。这是因为,当从池中调用连接对象上的 close() 时,只是简单地把连接返回池中以供重用,并没有实际关闭连接和关联的语句/结果集对象。
- 增加 java 堆 - 如果可能的话,我们也可尝试增加 java 堆,以观察是否能解决问题。
- 如果上述建议都不适用于该应用程序,那么,我们需要使用一个基于 JVMPI(JVM 事件探查器接口)的事件探查器(如 Jprobe 或 OptimizeIt)来找出哪些对象正在占用 java 堆。事件探查器还提供 java 代码中正在创建这些对象的位置的详细信息。本文档并不介绍每个事件探查器的详细信息。可以参考事件探查器文档来了解如何用事件探查器设置和启动应用程序。一般而言,基于 JVMPI 的事件探查器需要较高的系统开销,并会大大降低应用程序的性能。因此,在生产环境中使用这些事件探查器并不可取。
http://www.borland.com/optimizeit http://www.quest.com/jprobe
返回页首
对于本地 OOM 问题:
- 收集下列信息:
- .verbosegc 输出,通过它可监视 java 堆使用量。这样将有助于了解此应用程序的 java 内存要求。
应当注意,指定的最大堆内存量(在 java 命令行中使用 Xmx 标志)与应用程序的实际 java 堆使用量无关,其在 JVM 启动时被保留,并且此保留内存不能用于其它任何用途。
在使用 Jrockit 时,使用 -verbose 来代替 -verbosegc,因为这可以提供 codegen 信息以及 GC 信息。
-
定期记录进程虚拟内存大小,从启动应用程序时起直到 JVM 用完本地内存。这样将有助于了解此进程是否确实达到该操作系统的大小限值。
在 Windows 环境下,使用下列步骤来监视虚拟进程大小:
-
在“开始” -> “运行”对话框中,输入“perfmon”并单击“确定”。
-
在弹出的“性能”窗口中,单击“+”按钮(图表上部)。
-
在显示的对话框中选择下列选项:
在 Unix 或 Linux 环境下,对于一个给定 PID,可以使用以下命令来查找虚拟内存大小 - ps -p <PID> -o vsz。
在 Linux 环境下,单个 JVM 实例内的每个 java 线程都显示为一个独立的进程。如果我们获得根 java 进程的 PID,那么这就足够了。可以使用 ps 命令的 .forest 选项来找到根 java 进程。例如,ps lU <user> --forest 将提供一个由指定用户启动的所有进程的 ASCII 树图。您可以从该树图中找到根 java。
- 计算机中的内存可用性
如果计算机没有足够的 RAM 和交换空间,则操作系统将不能为此进程提供更多内存,这样也会导致内存不足。请确保 RAM 与磁盘中的交换空间之和足以满足该计算机中正在运行的所有进程的需要。
-
调整 java 堆
如果 java 堆使用量完全在最大堆范围内,则减小 java 最大堆将为 JVM 提供更多的本地内存。这不是一个解决办法,而是一个可尝试的变通方法。由于操作系统限制进程大小,我们需要在 java 堆和本地堆之间寻求一个平衡。
- JVM 的本地内存使用量
在加载了所有类并调用了方法(代码生成结束)后,JVM 的本地内存用量预计将会几乎达到稳定。对于大多数应用程序而言,这通常发生在最初几小时内。此后,JVM 可能会因加载运行时类型、生成优化代码等处理而仅使用少量本地内存。
为了缩小问题的范围,可尝试禁用运行时优化,并检查这是否会产生任何效果。
- 在使用 Jrockit 时,可使用 -Xnoopt 标志来禁用运行时优化。
- 在使用 SUN hotspot JVM 时,-Xint 标志将强迫 JVM 在解释模式中运行(不生成代码)。
如果在整个运行过程中,本地内存使用量继续不断增加,那么这可能是本地代码中的内存泄漏。
- 第三方本地模块或应用程序中的 JNI 代码
检查您是否在使用类似数据库驱动程序的任何第三方本地模块。这些本地模块也可以分配本地内存,泄漏可能从这些模块中发生。为了缩小问题的范围,应尝试在没有这些第三方模块的情况下重现问题。例如,可以使用纯 java 驱动程序来代替本地数据库驱动程序。
检查应用程序是否使用一些 JNI 代码。这也可能造成本地内存泄漏,如果可能的话,您可以尝试在没有 JNI 代码的情况下运行应用程序。
- 如果在执行上述步骤后还不能找到本地内存泄漏的根源,那么您需要与 JVM 供应商合作来获得一个特殊的编译版本,它可以跟踪本地内存分配调用,并可提供有关泄漏的更多信息。
| |
最近我在一个blaog上看到一个老兄关于displaytag解决大数据量的文章。他是用封装displaytag的方式写了一个displaytagpro。我个人觉得没有必要。一是封装后的即使解决了大数据量的问题,将来升级也是个问题,难道还有天天关注你的程序更新?二是其实displaytag已经解决了大数据量分页的问题。解决的补丁可以从这里下载
DISPL-134.zip 。该补丁增加了table的virtualSize属性。
解决方式大致如下:
jsp:
<display:table class="list" name="<%= CodeListAction.CODE_LIST_KEY %>" id="row" pageSize="20" virtualSize="<%= ((Integer)request.getAttribute (CodeListAction.CODE_LIST_SIZE_KEY)).toString() %>" requestURI="codelist.do" sort="list">
在数据量大时
可以设置virtualSize属性,表示总记录数。
action:// Get the page number requested
int page = 1;
int size = 20;
Enumeration paramNames = request.getParameterNames
();
while (paramNames.hasMoreElements()) {
String name = (String)paramNames.nextElement();
if (name != null && name.startsWith("d-") &&
name.endsWith("-p")) {
String pageValue = request.getParameter(name);
if (pageValue != null) {
page = Integer.parseInt(pageValue);
}
}
}
DB:
数据层你可以根据数据库的不同写不同的adapter。下面是针对oracle的特性写的。
select * from (
select query.*, rownum rnum from (
your complete query goes here....
) query where rownum <= (:pagingNo*:pagingSize)
) where rnum >= ((:pagingNo-1)*:pagingSize)+1 order by rnum
这样就可以了。该问题可以查看
http://jira.codehaus.org/browse/DISPL-134要想更好的控制分页,就用valuelist ,Extreme Table了。
风之语