lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2008年05月8日

配置独立运行的jsp预编译ant脚本

Filed under: Java,JAVA IDE,Resin,Tomcat — 标签:, , , , , — lizongbo @ 20:23

配置resin开启预编译jsp,在启动时,resin会自动编译jsp,出错信息在 stdout.log中。

[code]
<web-app id=”/lizongbo” document-directory=”webapps/lizongbo”>
<listener>
<listener-class>com.caucho.jsp.JspPrecompileListener</listener-class>
<init>
<extension>jsp</extension>
<extension>jspx</extension>
<extension>xtp</extension>
</init>
</listener>
</web-app>
[/code]

在开发过程,经常将页面传到resin上,才发现页面编译失败,浪费了不少时间,因此需要一个在本地预编译进行检查的操作。

resin 3.1以前的版本提供命令行方式进行jsp预编译。

完整的命令例子如下
%JAVA_HOME%\bin\java.exe -classpath %JAVA_HOME%\lib\tools.jar;D:\Java\resin-3.0.19\lib\aopalliance.jar;D:\Java\resin-3.0.19\lib\ejb-20.jar;D:\Java\resin-3.0.19\lib\ejb-30.jar;D:\Java\resin-3.0.19\lib\j2eedeploy.jar;D:\Java\resin-3.0.19\lib\jca-15.jar;D:\Java\resin-3.0.19\lib\jms-11.jar;D:\Java\resin-3.0.19\lib\jmx-12.jar;D:\Java\resin-3.0.19\lib\jsdk-24.jar;D:\Java\resin-3.0.19\lib\jstl-11.jar;D:\Java\resin-3.0.19\lib\jta-101.jar;D:\Java\resin-3.0.19\lib\portlet-10.jar;D:\Java\resin-3.0.19\lib\quercus.jar;D:\Java\resin-3.0.19\lib\resin-jdk15.jar;D:\Java\resin-3.0.19\lib\resin.jar;D:\Java\resin-3.0.19\lib\resinboot.jar;D:\Java\resin-3.0.19\lib\script-10.jar;D:\Java\resin-3.0.19\lib\webutil.jar;D:\Java\resin-3.0.19\plugins\resin-ant.jar com.caucho.jsp.JspCompiler -app-dir  E:\lizongbo\workspace\webapp E:\lizongbo\workspace\webapp
使用起来很不方便。(注意classpath里特意加了%JAVA_HOME%\lib\tools.jar,否则会报错,
出错信息如下:
Exception in thread “main” com.caucho.java.JavaCompileException: Resin can’t loa
d com.sun.tools.javac.Main.  Usually this means that the JDK tools.jar is missin
g from the classpath, possibly because of using a JRE instead of the JDK.  You c
an either add tools.jar to the classpath or change the compiler to an external o
ne with <java compiler=’javac’/> or jikes.

java.lang.ClassNotFoundException: com.sun.tools.javac.Main
at com.caucho.java.InternalCompiler.compileInt(InternalCompiler.java:77)
at com.caucho.java.AbstractJavaCompiler.run(AbstractJavaCompiler.java:101)
at java.lang.Thread.run(Thread.java:595)
)

resin 3.1.5及以后的版本终于提供了 ant方式的jspc的atsk,但是却有bug。
[code]
<project name=”test” default=”test” basedir=”.”>
<property name=”resin.home” value=”/usr/local/share/resin”/>

<target name=”test”>
<taskdef name=”resin-jspc”
classname=”com.caucho.ant.Jspc”>
<classpath>
<fileset dir=”${resin.home}”>
<include name=”plugins/resin-ant.jar”/>
<include name=”lib/*.jar”/>
</fileset>
</classpath>
</taskdef>

<resin-jspc rootDirectory=”/home/ferg/ws/dist/my-webapp”/>
</target>

</project>
[/code]
来源: http://wiki.caucho.com/Ant
在该方式下,会遇到提示说contentType重复定义的bug
出错信息如下:
E:\lizongbo\workspace\webapp\WEB-INF\ant\resin-jspc.xml:38:
com.caucho.jsp.JspLineParseException: /618119/test.jsp:6: contentType ‘text/vnd.wap.wml; charset=UTF-8’ conflicts with previous value of contentType ‘text/html; charset=UTF-8’.  Check the .jsp and any included .jsp files for conflicts.

原因是resin 3.1 对带BOM格式的UTF-8编码的jsp识别有问题。
参考: http://anotherbug.blog.chinajavaworld.com/entry/3683/0/

此时改页面是件痛苦的事情,于是想到使用Tomcat的ant jspC task

Tomcat 6.0.16的文件目录已经发生了变化,而官方的jspC的文档还没有更新:
http://tomcat.apache.org/tomcat-6.0-doc/jasper-howto.html

以前写过一篇笔记,基本是copy tomcat的官方文档
参考: http://blog.donews.com/lizongbo/archive/2005/06/06/413985.aspx
而现在主要用resin,因此想要一个可以独立进行jsp预编译的ant脚本,
所以手工清理后制作了个独立的jspc,方便随时预编译.

所用到的jar文件为:D:\Java\apache-tomcat-6.0.16\lib和D:\Java\apache-tomcat-6.0.16\bin 目录下所有jar
[code]
D:\Java\jspc\tomcat6lib 的目录

2008-05-08  20:09    <DIR>          .
2008-05-08  20:09    <DIR>          ..
2008-01-28  23:39            10,368 annotations-api.jar
2008-01-28  23:39            17,530 bootstrap.jar
2008-01-28  23:39            49,240 catalina-ant.jar
2008-01-28  23:39           122,869 catalina-ha.jar
2008-01-28  23:39           228,175 catalina-tribes.jar
2008-01-28  23:39         1,128,229 catalina.jar
2008-01-28  23:39             9,341 commons-daemon.jar
2008-01-28  23:39            27,699 el-api.jar
2008-01-28  23:39           102,129 jasper-el.jar
2008-01-28  23:39         1,395,270 jasper-jdt.jar
2008-01-28  23:39           511,240 jasper.jar
2008-01-28  23:39            72,408 jsp-api.jar
2008-01-28  23:39            85,287 servlet-api.jar
2008-01-28  23:39           742,089 tomcat-coyote.jar
2008-01-28  23:39           197,846 tomcat-dbcp.jar
2008-01-28  23:39            18,980 tomcat-juli.jar
16 个文件      4,718,700 字节
2 个目录    895,870,976 可用字节
[/code]

tomcat-jspc.bat的内容为:
(因为jsp文件太多,消耗内存较大,因此通过 ANT_OPTS=-Xmx512m 指定内存)
[code]
set ANT_OPTS=-Xmx512m
ant -f tomcat-jspc.xml -Dwebapp.name=mywebapp
[/code]
tomcat-jspc.properties的内容为:
[code]
webapp.root=E:/lizongbo/workspace
webapp.name = webapp
[/code]

tomcat-jspc.xml的内容如下:

[code]
<project name=”Webapp Precompilation” default=”all” basedir=”.”>
<property file=”${basedir}/tomcat-jspc.properties”/>
<property name=”tomcatlib.home” value=”${basedir}/tomcat6lib”/>
<property name=”webapp.path” value=”${webapp.root}/${webapp.name}”/>
<description> JSPC Tasks</description>
<taskdef resource=”org/apache/catalina/ant/catalina.tasks”>
<classpath>
<fileset file=”${tomcatlib.home}/tomcat-juli.jar”/>
<fileset file=”${tomcatlib.home}/jasper.jar”/>
<fileset file=”${tomcatlib.home}/jasper-el.jar”/>
<fileset file=”${tomcatlib.home}/el-api.jar”/>
<fileset file=”${tomcatlib.home}/jsp-api.jar”/>
<fileset file=”${tomcatlib.home}/servlet-api.jar”/>
<fileset file=”${tomcatlib.home}/catalina-ant.jar”/>
</classpath>
</taskdef>
<taskdef resource=”org/apache/catalina/ant/jmx/jmxaccessor.tasks”>
<classpath>
<fileset file=”${tomcatlib.home}/catalina-ant.jar”/>
</classpath>
</taskdef>
<typedef
name=”jmxEquals”
classname=”org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition”>
<classpath>
<fileset file=”${tomcatlib.home}/catalina-ant.jar”/>
</classpath>
</typedef>
<typedef
name=”jmxCondition”
classname=”org.apache.catalina.ant.jmx.JMXAccessorCondition”>
<classpath>
<fileset file=”${tomcatlib.home}/catalina-ant.jar”/>
</classpath>
</typedef>
<!– 先把WEB-INF/src下的java文件编译成class –>
<target name=”compilejava”>
<echo>jdk path: ${java.home} </echo>
<echo>webapp path: ${webapp.path} </echo>

<mkdir dir=”${webapp.path}/WEB-INF/classes”/>
<mkdir dir=”${webapp.path}/WEB-INF/lib”/>

<javac destdir=”${webapp.path}/WEB-INF/classes”
optimize=”off”
debug=”on” failonerror=”false”
encoding=”utf-8″ nowarn=”true” target=”1.5″
srcdir=”${webapp.path}/WEB-INF/src”
excludes=”**/*.smap”>
<classpath>
<pathelement location=”${webapp.path}/WEB-INF/classes”/>
<fileset dir=”${webapp.path}/WEB-INF/lib”>
<include name=”*.jar”/>
</fileset>
<pathelement location=”${tomcatlib.home}”/>
<fileset dir=”${tomcatlib.home}”>
<include name=”*.jar”/>
</fileset>
</classpath>
<include name=”**” />
<exclude name=”tags/**” />
</javac>

</target>
<!– 再把jsp页面生成java文件 –>
<target name=”jspc”>
<jasper
validateXml=”false”
uriroot=”${webapp.path}”
webXmlFragment=”${webapp.path}/WEB-INF/generated_web.xml”
outputDir=”${webapp.path}/WEB-INF/jspsrc” />

</target>
<!– 再把jsp的java代码编译成class –>
<target name=”compilejspjava”>

<mkdir dir=”${webapp.path}/WEB-INF/work”/>
<mkdir dir=”${webapp.path}/WEB-INF/lib”/>

<javac destdir=”${webapp.path}/WEB-INF/work”
optimize=”off”
debug=”on” failonerror=”true”
encoding=”utf-8″ nowarn=”true” target=”1.5″
srcdir=”${webapp.path}/WEB-INF/jspsrc”
excludes=”**/*.smap”>
<classpath>
<pathelement location=”${webapp.path}/WEB-INF/classes”/>
<fileset dir=”${webapp.path}/WEB-INF/lib”>
<!– need ignore mywebapp/WEB-INF/lib/servlet.jar 在这里忽略掉webapp lib里的低版本的servlet,以免编译失败–>
<exclude name=”servlet.jar”/>
<include name=”*.jar”/>
</fileset>
<pathelement location=”${tomcatlib.home}”/>
<fileset dir=”${tomcatlib.home}”>
<include name=”*.jar”/>
</fileset>
</classpath>
<include name=”**” />
<exclude name=”tags/**” />
</javac>

</target>

<target name=”all” depends=”compilejava,jspc,compilejspjava,cleanup”>
</target>

<target name=”cleanup”>
<delete includeEmptyDirs=”true”>
<fileset dir=”${webapp.path}/WEB-INF/jspsrc”/>
<fileset dir=”${webapp.path}/WEB-INF/work”/>
</delete>
</target>

</project>
[/code]

2007年12月4日

Tomcat遇到”Error listenerStart”或”Error filterStart”问题且无详细日志时的log配置.

Filed under: Java,Tomcat — 标签:, , — lizongbo @ 15:44

昨天部署web应用到Tomcat之后,无法成功启动,并且控制台没有详细的错误信息,
顶多就两行提示信息,例如:
严重: Error listenerStart
严重: Context [/lizongbo] startup failed due to previous errors

或者

严重: Error filterStart
org.apache.catalina.core.StandardContext start
严重: Context startup failed due to previous errors

查找logs目录下的信息,除了这两句话,也没别的辅助内容.
给查错带来了困难,在这种情况下,是因为Tomcat自身的默认日志没有将一些错误信息输出到控制台或文件,
这个时候则需要配置Tomcat自身的log,启用详细的调试日志.

在Tomcat 5.5和Tomcat 6.0中的配置基本一样,只是相关文件放的目录有所不同.

首先需要准备的文件为:

1.log4j.jar , 下载地址 : http://www.apache.org/dist/logging/log4j/1.2.15/apache-log4j-1.2.15.zip
2.Tomcat 5.5所需的 commons-logging.jar,下载地址: http://www.apache.org/dist/commons/logging/binaries/commons-logging-1.1.zip

3.log4j配置文件:
log4j.properties
配置内容为:

log4j.rootLogger=ERROR,R

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%p]%t-%c-%m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${catalina.home}/logs/lizongbo.log
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[%p]%t-%c-%m%n

log4j.logger.org.apache.catalina=INFO,R,CONSOLE

#日志级别不能太低,如果配置为debug的话,输出的日志信息太多,导致tomcat启动非常的慢.

4.Tomcat 6.0所需的juli替换文件:
http://www.apache.org/dist/tomcat/tomcat-6/v6.0.14/bin/extras/tomcat-juli-adapters.jar
http://www.apache.org/dist/tomcat/tomcat-6/v6.0.14/bin/extras/tomcat-juli.jar

在Tomcat6.0中,

将tomcat-juli-adapters.jar,log4j-1.2.15.jar,log4j.properties复制到D:\Java\ApacheTomcat6.0.14\lib下面.

将tomcat-juli.jar复制到D:\Java\apache-tomcat-6.0.14\bin\下面.

然后启动tomcat,就可以在D:\Java\apache-tomcat-6.0.14\logs下看到lizongbo.log了.

在 Tomcat5.5中,

将commons-logging-1.1.jar,log4j-1.2.15.jar,复制到D:\Java\apache-tomcat-5.5.25\common\lib下面.
将log4j.properties复制到D:\Java\apache-tomcat-5.5.25\common\classes下面.

然后启动tomcat,就可以在D:\Java\apache-tomcat-5.5.25\logs下看到lizongbo.log了.

在这个时候,再通过日志文件来分析,则会发现出现这种错误的情况可能有:
(以下是我遇到的出错情况,大多是些低级错误)
1.webapps要用到的classe文件根本没有复制到WEB-INF/classes目录下面
(java.lang.NoClassDefFoundError,而这个信息可能默认没输出到控制台,尤其是用了spring的,昨天就是这个粗心的低级错误)
2.要用到lib文件没有复制完,缺少lib
3.lib下的同一个库的jar文件存在多个不同版本,引起版本冲突.
4.lib下的jar与tomcat版本不相对应(我遇到的问题是web应用在Tomcat5.5上运行正常,换到Tomcat6.0上就出错,
例如一个用了struts的webapp在Tomcat 6上报下面的错误
“Parse Fatal Error at line 17 column 6: The processing instruction
target matching “[xX][mM][lL]” is not allowed” )

愿意看英文的可以参考官方网站说明:
http://tomcat.apache.org/tomcat-6.0-doc/logging.html
http://tomcat.apache.org/tomcat-5.5-doc/logging.html

2007年11月13日

对tomcat cluster集群配置中session复制用法的一个误解

一直以来,我误解认为启动了n个tomcat,则Session需要同步复制到n个Tomcat中存在,因此在启动了6个以上的Tomcat,性能会大大下降。

而实际情况下,采取Apache 加Tomcat进行负载均衡集群的时候,是可以不用将Session复制到所有的节点里,

比如有六个Tomcat实例

Tomcat1,Tomcat2,Tomcat3,Tomcat4,Tomcat5,Tomcat6

是可以配置成 三组互相复制Session的群组,
比如Tomcat1和Tomcat2互相同步Session,
比如Tomcat3和Tomcat4互相同步Session,
比如Tomcat5和Tomcat6互相同步Session.

再在Apache的mod_jk模块里,对每个worker配置上redirect和activation属性。

将Tomcat1,Tomcat3,Tomcat5做为对外正常提供服务器的Tomcat,

Tomcat2,Tomcat4,Tomcat6作为分别对应的灾难恢复的备份Tomcat.

即比如Tomcat1当机之后,Apache会自动将发给Tomcat1的请求转发到Tomcat2上,
而Tomcat2因为同步了Tomcat1的Session信息,因此从用户的角度,是感觉不出任何差异的。

单纯的Tomcat测试如下:

Tomcat配置:

Tomcat1. port=”15080″, jvmRoute=”tomcat1″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.5″
port=”45564″
frequency=”500″
dropTime=”3000″/>

Tomcat2. port=”16080″, jvmRoute=”tomcat2″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.5″
port=”45564″
frequency=”500″
dropTime=”3000″/>

Tomcat3. port=”17080″, jvmRoute=”tomcat3″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.6″
port=”45564″
frequency=”500″
dropTime=”3000″/>

Tomcat4. port=”18080″, jvmRoute=”tomcat4″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.6″
port=”45564″
frequency=”500″
dropTime=”3000″/>

Tomcat5. port=”19080″, jvmRoute=”tomcat5″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.7″
port=”45564″
frequency=”500″
dropTime=”3000″/>

Tomcat6. port=”20080″, jvmRoute=”tomcat6″,
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.7″
port=”45564″
frequency=”500″
dropTime=”3000″/>

所有的Tomcat webapp的web.xml加上<distributable />

(例如D:\Java\Tomcat2\webapps\examples\WEB-INF\web.xml ,)

测试页面为:

第一组:
http://localhost:15080/examples/servlets/servlet/SessionExample
http://localhost:16080/examples/servlets/servlet/SessionExample

第二组:
http://localhost:17080/examples/servlets/servlet/SessionExample
http://localhost:18080/examples/servlets/servlet/SessionExample

第三组:
http://localhost:19080/examples/servlets/servlet/SessionExample
http://localhost:20080/examples/servlets/servlet/SessionExample

在每一组中,打开其中任何一个链接,然后设置属性值,
都可以在访问另外一个链接的时候得到。对应的sessionid的后缀会变成对应Tomcat的jvmRoute.
(以上测试的tomcat均在同一台服务器上)

接下来再配置Apache的mod_jk.

workers.properties的内容节选如下:

(重点是redirect和activation两个属性)

worker.tomcat1.port=15009
worker.tomcat1.host=127.0.0.1
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor=1
worker.tomcat1.redirect=tomcat2

worker.tomcat2.port=16009
worker.tomcat2.host=10.108.20.126
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor=1
worker.tomcat2.redirect=tomcat1
worker.tomcat2.activation=disabled

详细参考:

http://tomcat.apache.org/connectors-doc/generic_howto/loadbalancers.html

备注:Tomcat6已经没有使用JGroups来实现集群复制,

而是使用Apache Tribes 来实现该效果的。
Apache Tribes的介绍在:
http://tomcat.apache.org/tomcat-6.0-doc/tribes/introduction.html

为了简便配置,因此只使用一份Tomcat,使用不同的cofig来启动,配置好的文件在:

http://618119.com/docs/Tomcat/TomcatCluster.zip

下载解压到Tomcat(例如D:\Java\apache-tomcat-6.0.14)目录里,运行对应的bat文件即可:
start15080.bat
start16080.bat
start17080.bat
start18080.bat
start19080.bat
start20080.bat

Older Posts »

Powered by WordPress