行云无鸣

2012-03-20

Jetty下的struts2报”There is no Action mapped ……”

Filed under: 乱语 — 标签:, , , — hellyguo @ 13:48

在tomcat下正常运行的程序,在jetty下运行异常,报无法找到Struts的ACTION:“There is no Action mapped for namespace / and action name ”。
通过打开struts的devMode,打开struts2的日志和xwork2的日志,终于定位问题:
在web.xml里面指定了struts配置文件struts.xml的路径,写的是“/conf/struts/struts.xml”。这样写,在tomcat下能正常运行,但在jetty下,无法加载,所有配置无法读取到。所以无法找到任何action。改为“conf/struts/struts.xml”就可以了。
总结:jetty的类加载器,比tomcat的加载器要严格。

2009-12-10

原来Tomcat的webapp启动顺序是依赖File.list()方法的

Filed under: 乱语 — 标签:, , , , , , — hellyguo @ 20:58

公司开发了一套系统,分多个模块,部署于客户提供WebSphere上,通过设置启动顺序,可以正常运行。现在要搭建模拟演示系统,搭建在公司自己的Linux下。公司没有WebSphere的Linux版(有也不能用,没license),就选择部署在Tomcat下。
本来我们开发也是在Windows下的Tomcat调试的,完全没问题。结果部署到Linux下,问题来了,启动顺序完全不是预期的顺序!
在Windows下,我们是将配置好的xml文件放置于conf/Catalina/localhost,按启动顺序命名为1.xx_a.xml/2.xx_b.xml/3.xx_c.xml/4.xx_d.xml。这样,系统就能正常在Tomcat下运行起来。可是,这样设置,在公司服务器上就是不行!启动顺序一直不是1-2-3-4,而是4-2-3-1。
一开始以为是Tomcat版本问题,虽然Windows下版本和Linux下版本均为5.0.28,我还是为将Linux下的版本升级到了6.0.20。可惜,无济于事。
在网上搜索关于Tomcat启动顺序的文章,都说Tomcat是按字母顺序加载配置文件的。可怎么设置都没有用。在被Tomcat折磨了一天半后,我开始寄希望于有开源的J2EE容器,可以像WebSphere一样,设置启动顺序。在逐一安装了jetty,jonas,jboss,resin,glassfish后,我悲哀地发现,所有这些,都不支持对应用设置启动顺序。
最后尝试了WebLogic。昨天深夜,挂机下载WebLogic 10.3。今天上午安装后发现,WebLogic和WebSphere一样,也能设置启动顺序。很兴奋,想用,但还是打了退堂鼓(也没有license,不能也不敢用)。
最后一条路了,翻看Tomcat的源代码。
下载了Tomcat6.0.20的源代码,在HostConfig.java中找到了那块加载xml的代码。
Line490:

// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
// Deploy WARs, and loop if additional descriptors are found
deployWARs(appBase, appBase.list());
// Deploy expanded folders
deployDirectories(appBase, appBase.list());

原来启动顺序就是File.list()的顺序!
又下载Tomcat5.0.28的源代码,查看HostConfig.java,还是如此:
Line426:

String configFiles[] = configBase.list();

Line430:

String files[] = appBase.list();

Line568:

deployDescriptors(configBase(), configBase.list());

Line813:

String files[] = appBase.list();

Line989:

String configFiles[] = configBase.list();

确认了,Tomcat的加载的确是与File.list()有关。
写了个测试代码确认问题:
Test.java

package fileClass_listMethod;

import java.io.File;

public class Test {
public static void main(String args[]) throws Exception {
File file = new File(“.”);
String[] files = file.list();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
}
}

这个程序的输出,在大部分操作系统中,是相同的。但的确是存在不同的情况,我,就中奖了。
公司服务器,RHEL4

$ uname -a
Linux xxxweb2008.localdomain 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39 EST 2005 i686 i686 i386 GNU/Linux
$ java -version
java version “1.5.0_12”
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_12-b04)
Java HotSpot(TM) Server VM (build 1.5.0_12-b04, mixed mode)
$ java Test
Test.java
4.xx_d.xml
2.xx_b.xml
Test.class
1.xx_a.xml
3.xx_c.xml

我的T400,WinXPSP3

2600.xpsp_sp3_gdr.090804-1435 : Service Pack 3
>java –version
java version “1.5.0_07”
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-b03)
Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode, sharing)
>java Test
1.xx_a.xml
2.xx_b.xml
3.xx_c.xml
4.xx_d.xml
Test.class
Test.java

我的虚拟机Linux,Debian 5.02

$ uname -a
Linux debian.vmware 2.6.26-2-686 #1 SMP Wed Aug 19 06:06:52 UTC 2009 i686 GNU/Linux
$ java -version
java version “1.6.0_12”
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Client VM (build 11.2-b01, mixed mode)
$ java Test
1.xml
2.xml
3.xml
Test.class
Test.java

由此可见,网上说的Tomcat启动顺序是基于字母顺序,并不准确。严格说,是基于操作系统的底层实现。基于字母顺序,只是大多数系统的情况。查看JavaDoc,明确说明了此点:
list
public String[] list()
返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
如果此抽象路径名并不表示一个目录,则此方法将返回 null。否则,为目录中的每个文件或目录返回一个字符串数组。表示目录本身及其父目录的名称不包括在结果中。每个字符串是一个文件名,而不是一条完整路径。
不保证所得数组中的相同字符串将以特定顺序出现,特别是不保证它们按字母顺序出现。
返回:
由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。如果目录为空,则数组也将为空。如果抽象路径名不表示一个目录,或者发生 I/O 错误,则返回 null。
抛出:
SecurityException – 如果存在安全管理器,且其 SecurityManager.checkRead(java.lang.String) 方法拒绝对目录进行读取访问
直接修改Tomcat5.0.28的HostConfig.java
Line427:

String configFiles[] = configBase.list();
Arrays.sort(configFiles, 0, configFiles.length);
deployDescriptors(configBase, configFiles);

Line432:

String files[] = appBase.list();
Arrays.sort(files, 0, files.length);
deployWARs(appBase, files);

Line571:

String[] cfgFiles = configBase.list();
Arrays.sort(cfgFiles, 0, cfgFiles.length);
deployDescriptors(configBase(), cfgFiles);

Line818:

String files[] = appBase.list();

if (files != null) {
Arrays.sort(files, 0, files.length);

Line995:

String configFiles[] = configBase.list();
Arrays.sort(configFiles, 0, configFiles.length);
deployDescriptors(configBase, configFiles);

重新更新了catalina.jar后,启动Tomcat5.0.28,应用按排定顺序正常启动。
也修改了Tomcat6.0.28的HostConfig.java:
Line491:

// Deploy XML descriptors from configBase
String[] configFiles = configBase.list();
Arrays.sort(configFiles, 0, configFiles.length);
deployDescriptors(configBase, configFiles);
// Deploy WARs, and loop if additional descriptors are found
String[] appFiles = appBase.list();
Arrays.sort(appFiles, 0, appFiles.length);
deployWARs(appBase, appFiles);
// Deploy expanded folders
deployDirectories(appBase, appFiles);

update:我将这点作为增强点提交到Tomcat的bugzilla了,URL
update:提交被否决了,认为Web程序都是独立的,不应该依赖于加载顺序。

2009-02-26

打算废弃Windows,全面转入Linux(Debian)

Filed under: 未分类 — 标签:, , , , , — hellyguo @ 23:47

自从前日系统过慢停掉了IBM的两个关键服务,TPM和TSSCore,昨天早上打开休眠的机器时,T61就死活不让我登录。无论是刷指纹还是输入密码,都不行。得,服务停得真准!
懒得去搞,就先切换到了Linux下进行必要的处理,工作。
下午不得已必须进入Windows了,在网络和PE的帮助下,用PE下的注册表编辑器修改了硬盘上的注册表文件system,开启了TPM和TSSCore,终于进入了Windows。但运行Eclipse3.2+MyEclipse5.5+Tomcat5+Oracle10g,还是抗不住。死心了。
思前想后,打算正式切换到Linux下了。
在Debian下下载了Eclipse3.4.1,WTP死活掉不起从apt上拿下来的tomcat5.5,看网上资料,说是Debian自带的Tomcat5.5的确存在该问题,必须从Apache.org下载tar.gz。
想想自己公司服务器上有,就用sftp去下。
公司服务器不是默认的22,需要改变端口,折腾了半天没连上,结果原因竟然是参数顺序错了:
我先打的是:
sftp root@www.xxx.com -o Port=nnnn
应该是:
sftp -o Port=nnnn root@www.xxx.com
又学了一招

2008-09-30

WAS6报"Cannot forward. Response already committed."的解决方法

Filed under: 未分类 — 标签:, , — hellyguo @ 18:45

说明:

在某项目中,我们使用了WAS6,框架采用的是Struts+Spring+iBatis。在某块代码中,由于要定制某些输出,对response进行了设置及直接通过response输出。执行时,就会报错,报:Response already committed。

解决办法:

将return mapping.findForward(…);改为return null;即可。

原因:

要么生成输出内容,要么转向或重定向。这两种行为,只能二选一。WAS6较严格,对这个严格控制。而TOMCAT5.0.28,对这个控制不严格。

参考:

WAS 6.0 – Response already committed / OutputStream already obtained

%d 博主赞过: