Ubuntu 16.04下Tomcat 7.0.68启动服务时候报告“java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;”

在使用Ubuntu16.04 安装openjdk-7-jdk介绍的方式切换Java1.7版本后,在进行代码调试的时候,Tomcat 7.0.68报告如下错误:

java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
at org.apache.catalina.core.ApplicationContext.getInitParameterNames(ApplicationContext.java:368)
at org.apache.catalina.core.ApplicationContextFacade.getInitParameterNames(ApplicationContextFacade.java:367)
at org.springframework.web.context.support.WebApplicationContextUtils.registerEnvironmentBeans(WebApplicationContextUtils.java:229)
at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.postProcessBeanFactory(AbstractRefreshableWebApplicationContext.java:165)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:520)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5068)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5584)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1859)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:618)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:565)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
at sun.rmi.transport.Transport$2.run(Transport.java:202)
at sun.rmi.transport.Transport$2.run(Transport.java:199)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:198)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:567)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(TCPTransport.java:619)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:684)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:681)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:681)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)

这说明Ubuntu 16.04下的Tomcat是在Java 8环境下面编译的,尽管我们已经切换到Java 7下面了,但是Tomcat并不能很好的执行我们的Java 7代码。这个时候的解决方法就是,编译代码的时候指定Java 7,但是在Tomcat执行的时候,指定使用Java 8来运行。

参考链接


Java error java.util.concurrent.ConcurrentHashMap.keySet

Ubuntu 14.04隐藏Tomcat-7.0.52的版本号与操作系统类型

推荐方案

另外更推荐的方法是通过 Tomcat 的配置文件完成,而不是修改代码,具体配置方法为:

conf/server.xml 配置文件中的 <Host> 配置项中添加如下配置:

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" />

配置项说明:

  • showReport:默认值为true,默认显示报错信息
  • showServerInfo:默认值为true,默认显示Tomcat的版本号

其他方案

一般情况下,软件的漏洞信息和特定版本,特定操作系统是相关的,因此,软件的版本号以及操作系统类型对攻击者来说是很有价值的。

在默认情况下,Tomcat会在返回信息中把自身的版本号,操作系统类型都显示出来,如下图:
TomcatErrorPageVersion

这样做会造成潜在的安全风险,导致不必要的攻击行为。

Ubuntu 14.04系统上隐藏Tomcat-7.0.52的版本号与操作系统类型的方法如下:

$ cd ~

$ mkdir catalina

$ cd catalina

$ cp /usr/share/tomcat7/lib/catalina.jar .

$ unzip catalina.jar

$ cd org/apache/catalina/util

$ vim ServerInfo.properties

可以看到里面的内容如下:

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

server.info=Apache Tomcat/7.0.52 (Ubuntu)
server.number=7.0.52.0
server.built=Jun 30 2016 01:59:37

直接注释掉里面的内容,如下:

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# server.info=Apache Tomcat/7.0.52 (Ubuntu)
# server.number=7.0.52.0
# server.built=Jun 30 2016 01:59:37

修改完成后,把修改完成的数据存储到catalina.jar中。

$ cd ~

$ cd catalina

$ jar uvf catalina.jar org/apache/catalina/util/ServerInfo.properties

把修改后的catalina.jar放回到Tomcat的目录下面:

$ cd ~

$ cd catalina

$ sudo unlink /usr/share/tomcat7/lib/catalina.jar 

$ sudo mv /usr/share/java/catalina.jar /usr/share/java/catalina.jar.old

$ sudo cp catalina.jar /usr/share/java/

$ sudo chmod +r /usr/share/java/catalina.jar

$ cd /usr/share/tomcat7/lib

$ sudo ln -s ../../java/catalina.jar catalina.jar

重启Tomcat的服务

$ sudo service tomcat7 restart

修改后的结果如下图所示,已经没有系统类型信息了,仅仅返回了一个404错误。

TomcatErrorPageVersionAfterHide

至于如何隐藏Apache的版本号,参考链接 Ubuntu 14.04隐藏Apache-2.4的版本号与操作系统类型

参考链接


Tomcat隐藏版本号和报错信息(修改配置文件方式)

在Ubuntu 14.04 系统中的Apache Tomcat上部署Apache Archiva 2.2.1

注意: Apache Archiva 2024-02 开始已经停止维护 建议使用 JFrog Artifactory 替代。

简介


Apache Archiva是一套可扩展的Artifact Repository管理系统。它能够与MavenContinuumANT等构建工具完美结合。Archiva提供的功能包括:远程Repository代理,基于角色的安全访问管理,Artifact分发、维护、查询,生成使用报告,提供基于Web的管理界面等。 本来是Sonatype Nexus更加方便的,但是可惜最新的版本不支持在Tomcat中使用了,因此只能转而使用Apache Archiva

操作步骤


1.下载Apache Archiva

Apache官方网站下载,下载其中的War包。如下图: DownloadArchivaHtml 也可以在本站下载. 具体的命令如下:

$ wget https://www.mobibrw.com/wp-content/uploads/2016/07/apache-archiva-2.2.1.war_.zip

$ unzip apache-archiva-2.2.1.war_.zip

$ sudo mv apache-archiva-2.2.1.war /var/lib/tomcat7/webapps/archiva.war

 

2.下载Apache Archiva依赖的Jar包

Apache Archiva需要依赖derby-10.10.1.1.jar(或更高版本)(org.apache.derby:derby:10.10.1.1), activation-1.1.jar(javax.activation:activation:1.1),mail-1.4.jar(javax.mail:mail:1.4.7).可以在MVN Repository官网下载。也可以在本站打包下载。 下载完成后,需要放到Tomcat的安装目录下面的lib目录下。 具体的命令如下:

$ wget https://www.mobibrw.com/wp-content/uploads/2016/07/ArchivaArchiveJars.zip

$ unzip ArchivaArchiveJars.zip

$ sudo mv activation-1.1.jar /usr/share/tomcat7/lib

$ sudo mv derby-10.10.1.1.jar /usr/share/tomcat7/lib

$ sudo mv mail-1.4.7.jar /usr/share/tomcat7/lib

 

3.配置Apache Archiva

(1)停止Tomcat,后续的操作是先关闭Tomcat为前提的。

$ sudo service tomcat7 stop

(2)把下载到的apache-archiva-2.2.1.war重命名成archiva.war然后放到Tomcat安装目录下的webapps目录下面。

$ wget https://www.mobibrw.com/wp-content/uploads/2016/07/apache-archiva-2.2.1.war_.zip

$ unzip apache-archiva-2.2.1.war_.zip

$ sudo mv apache-archiva-2.2.1.war /var/lib/tomcat7/webapps/archiva.war

(3)在Tomcat的配置文件中增加两项appserver.homeappserver.base,两者都指向相同的目录即可,本例中,都指向了/data/Archiva这个目录。

$ mkdir /data/Archiva

$ sudo vim /usr/share/tomcat7/bin/setenv.sh

在脚本的第一行执行代码中增加如下内容:

export CATALINA_OPTS="-Dappserver.home=/data/Archiva -Dappserver.base=/data/Archiva"

注意:不要直接修改catalina.sh这个文件,原因在于这个文件每次更新都可能会被替换掉,环境变量的设置都应该在setenv.sh中设置。
注意catalina.sh这个文件中的如下注释

#   Do not set the variables in this script. Instead put them into a script
#   setenv.sh in CATALINA_BASE/bin to keep your customizations separate.

(4)由于Apache Archiva 2.2.1BUG,他没有自动创建必须的目录,导致如果这个目录不存在会初始化失败。因此我们需要手动创建这些目录。

$ mkdir /data/Archiva/conf

$ mkdir /data/Archiva/derby

$ mkdir /data/Archiva/logs

$ chown -R tomcat7:tomcat7 /data/Archiva/

(5)在Tomcat的配置目录下的Catalina\localhost目录下面创建一个名为archiva.xml的配置文件.

$ sudo vim /etc/tomcat7/Catalina/localhost/archiva.xml

里面的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/data/Archiva/derby" 
	docBase="${catalina.base}/webapps/archiva.war">
	<Resource name="jdbc/users" auth="Container" type="javax.sql.DataSource"
		username="sa"
		password=""
		driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
		url="jdbc:derby:/data/Archiva/derby/db;create=true" />

	<Resource name="mail/Session" auth="Container"
		type="javax.mail.Session"
		mail.smtp.host="localhost"/>
</Context>

注意其中的Context path为数据库相关配置文件所在的路径,包含配置,数据库等等很多文件,url为数据库的具体存储目录,仅仅包含数据库数据。 注意:Ubuntu系统下面CATALINA_HOME指向/usr/share/tomcat7,而CATALINA_BASE指向/var/lib/tomcat7

(6)启动或者重启Tomcat,等待几分钟之后,即可成功配置完成。

$ sudo service tomcat7 start

如下图: ApacheArchivaIndexPage 注意,如果在最后一步发生失败,那么我们需要删除/data/Archiva这个目录,以及Tomcat安装目录下面的webapps\archiva这两个目录,原因是在配置过程中修改了部分文件,如果不删除这几个文件,会导致各种异常。

注意,上图中的"Create Admin User"按钮,当创建用户的时候,貌似用户名是可以不用"admin"的,但是,实际上,管理员的用户名是不变的,不管你输入什么,最后登陆的时候填写的用户名,永远必须是"admin",否则会一直提示用户名或密码不正确。

注意,如果使用Apache Httpd(Apache 2.x)作为前端代理Tomcat的情况下部署Apache Archiva,并且使用AJPApache JServ Protocol)的方式进行通信,那么在配置Apache Httpd(Apache 2.x)的配置文件的时候,里面写入的名字必须严格跟Tomcat中部署的名字一致,比如,如果Tomcat配置的时候是archiva,那么在Apache Httpd(Apache 2.x)的配置文件中,也必须使用archiva,不能像其他简单项目一样进行命名重定向。如下:

$ sudo vim /etc/apache2/sites-available/000-default.conf

里面增加的AJP代理信息如下:

#for Apache Archiva
#此处的名字不可改变,对于Apache Archiva,由于他会进行304重定向,因此
#如果这里的名字跟Tomcat中部署的如果不同名,那么会出现登陆后无法进入控制
#页面的问题
ProxyPass /archiva/ ajp://127.0.0.1:8009/archiva/
ProxyPassReverse /archiva/ ajp://127.0.0.1:8009/archiva/

更详细的配置说明,参考 Ubuntu 13.10 Apache 2.2 通过 AJP 整合 Tomcat 7

客户端配置


在客户机上找到.m2所在的目录,找到settings.xml这个配置文件,如果不存在,则手工创建,里面的默认内容如下:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
            http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <localRepository/>
    <interactiveMode/>
    <usePluginRegistry/>
    <offline/>
    <pluginGroups/>
    <servers/>
    <mirrors/>
    <proxies/>
    <profiles/>
    <activeProfiles/>
</settings>

在其中的mirrors中间增加如下内容:

<mirror>
	<id>internal</id>
	<name>Archiva Managed Internal Repository</name>
	<url>http://www.mobibrw.com/archiva/repository/internal</url>
	<mirrorOf>*</mirrorOf>
</mirror>

修改后的内容变成如下样子:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
            http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <localRepository/>
    <interactiveMode/>
    <usePluginRegistry/>
    <offline/>
    <pluginGroups/>
    <servers/>
    <mirrors>
		<mirror>
			<id>internal</id>
			<name>Archiva Managed Internal Repository</name>
			<url>http://www.mobibrw.com/archiva/repository/internal</url>
			<mirrorOf>*</mirrorOf>
		</mirror>
	</mirrors>
    <proxies/>
    <profiles/>
    <activeProfiles/>
</settings>

目前使用的时候,发现,在Apache Archiva刚刚配置完成后,是没办法进行访问的,这个时候一切都返回404,等服务器启动几个小时之后,从中央服务器同步完成数据了,就可以进行访问了,这个问题纠结了好久,最后发现只要等待就可以了,不知道是不是一个通病。
另外就是,在Apache Archiva的搜索页面中使用Search,如果是第一次使用,会发现搜索任何包都提示找不到,原因是因为在设计的时候,只搜索本地已经下载过的包,而在中央仓库中的包是不搜索的,因此会一直提示找不到任何包,只要有任何的客户端调用过,那么就可以在搜索页中找到了,这个问题不必纠结。

引用链接


在Windows 7系统中的Apache Tomcat 7.0.68上部署Apache Archiva 2.2.1

简介

注意: Apache Archiva 2024-02 开始已经停止维护 建议使用 JFrog Artifactory 替代。


Apache Archiva是一套可扩展的Artifact Repository管理系统。它能够与MavenContinuumANT等构建工具完美结合。Archiva提供的功能包括:远程Repository代理,基于角色的安全访问管理,Artifact分发、维护、查询,生成使用报告,提供基于Web的管理界面等。

本来是Sonatype Nexus更加方便的,但是可惜最新的版本不支持在Tomcat中使用了,因此只能转而使用Apache Archiva

操作步骤


1.下载Apache Archiva

Apache官方网站下载,下载其中的War包。如下图:

DownloadArchivaHtml

也可以在本站下载.

2.下载Apache Archiva依赖的Jar包

Apache Archiva需要依赖derby-10.10.1.1.jar(或更高版本)(org.apache.derby:derby:10.10.1.1), activation-1.1.jar(javax.activation:activation:1.1),mail-1.4.jar(javax.mail:mail:1.4.7).可以在Mvn Repository官网下载。也可以在本站打包下载

下载完成后,需要放到Tomcat的安装目录下面的lib目录下。

3.配置Apache Archiva

(1)停止Tomcat,后续的操作是先关闭Tomcat为前提的。
(2)把下载到的apache-archiva-2.2.1.war重命名成archiva.war然后放到Tomcat安装目录下的webapps目录下面。
(3)在开始菜单中找到Tomcat的配置项Configure Tomcat,然后增加两项appserver.homeappserver.base,两者都指向相同的目录即可,本例中,都指向了D:\Archiva这个目录。具体如下图:
ApacheTomcat7Properties
(4)由于Apache Archiva 2.2.1BUG,他没有自动创建一个名为conf的目录,导致如果这个目录不存在会初始化失败。因此我们需要手动创建D:\Archiva\conf这个目录。
(5)在Tomcat的安装目录下的conf\Catalina\localhost目录下面创建一个名为archiva.xml的配置文件,里面的内容如下:

<Context path="d:/archiva/derby" 
	docBase="${catalina.home}/webapps/archiva.war">
	<Resource name="jdbc/users" auth="Container" type="javax.sql.DataSource"
		username="sa"
		password=""
		driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
		url="jdbc:derby:d:/archiva/derby/db;create=true" />

	<Resource name="mail/Session" auth="Container"
		type="javax.mail.Session"
		mail.smtp.host="localhost"/>
</Context>

注意其中的Context path为数据库相关配置文件所在的路径,包含配置,数据库等等很多文件,url为数据库的具体存储目录,仅仅包含数据库数据。
(6)启动或者重启Tomcat,等待几分钟之后,即可成功配置完成。如下图:
ApacheArchivaIndexPage
注意,如果在最后一步发生失败,那么我们需要删除D:\Archiva这个目录,以及Tomcat安装目录下面的webapps\archiva这两个目录,原因是在配置过程中修改了部分文件,如果不删除这几个文件,会导致各种异常。

注意上图中的"Create Admin User"按钮,当创建用户的时候,貌似用户名是可以不用"admin"的,但是,实际上,管理员的用户名是不变的,不管你输入什么,最后登陆的时候填写的用户名,永远必须是"admin",否则会一直提示用户名或密码不正确。

引用链接


Ubuntu 12.04 系统下设置Tomcat 7服务器上JVM的内存大小

以前都是正常的Tomcat 7服务器,在增加了一个新工程后,无法正常访问,查看日志:

$ cat /var/log/tomcat7/catalina.out

可以看到如下错误信息:

SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
        at java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.util.concurrent.FutureTask.get(FutureTask.java:188)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1128)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:782)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1566)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1556)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.OutOfMemoryError: Java heap space
        at java.util.zip.InflaterInputStream.<init>(InflaterInputStream.java:88)
        at java.util.zip.ZipFile$ZipFileInflaterInputStream.<init>(ZipFile.java:389)
        at java.util.zip.ZipFile.getInputStream(ZipFile.java:370)
        at java.util.jar.JarFile.getInputStream(JarFile.java:412)
        at org.apache.tomcat.util.scan.FileUrlJar.getEntryInputStream(FileUrlJar.java:96)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1922)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1891)
        at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1877)
        at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1270)
        at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:855)
        at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:345)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5161)
        ... 7 more

说明Tomcat在增加新工程后,内存不足了。

解决方法如下:

修改/etc/default/tomcat7文件:

$ sudo vim /etc/default/tomcat7

找到如下信息:

# The home directory of the Java development kit (JDK). You need at least
# JDK version 1.5. If JAVA_HOME is not set, some common directories for
# OpenJDK, the Sun JDK, and various J2SE 1.5 versions are tried.
#JAVA_HOME=/usr/lib/jvm/openjdk-6-jdk

# You may pass JVM startup parameters to Java here. If unset, the default
# options will be: -Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC
#
# Use "-XX:+UseConcMarkSweepGC" to enable the CMS garbage collector (improved
# response time). If you use that option and you run Tomcat on a machine with
# exactly one CPU chip that contains one or two cores, you should also add
# the "-XX:+CMSIncrementalMode" option.
JAVA_OPTS="-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC"

可以看到,目前限制的内存最大值为128MB,-Xmx128m,调整到256MB后重启Tomcat7。

$ sudo service tomcat7 restart

解决问题。

修改Tomcat Connector运行模式,优化Tomcat运行性能

Tomcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一。不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio、nio、apr三种运行模式,那么这三种运行模式有什么区别呢,我们又如何修改Tomcat Connector的运行模式来提高Tomcat的运行性能呢?
下面,我们先大致了解Tomcat Connector的三种运行模式。

bio


bio(blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,就是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。我们可以通过Tomcat Manager来查看服务器的当前状态。【点击这里可以查看Tomcat Manager用户配置的相关信息】

tomcat-status-bio

nio


nio(new I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。要让Tomcat以nio模式来运行也比较简单,我们只需要在Tomcat安装目录/conf/server.xml文件中将如下配置:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

中的protocol属性值改为org.apache.coyote.http11.Http11NioProtocol即可:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />

此时,我们就可以在Tomcat Manager中看到当前服务器状态页面的HTTP协议的Connector运行模式已经从http-bio-8080变成了http-nio-8080tomcat-status-nio

apr


apr(Apache Portable Runtime/Apache可移植运行时),是Apache HTTP服务器的支持库。你可以简单地理解为,Tomcat将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能。 Tomcat apr也是在Tomcat上运行高并发应用的首选模式。如果我们的Tomcat不是在apr模式下运行,在启动Tomcat的时候,我们可以在日志信息中看到类似如下信息:

2013-8-6 16:17:49 org.apache.catalina.core.AprLifecycleListener init
信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: xxx/xxx(这里是路径信息)

Tomcat apr运行模式的配置是三种运行模式之中相对比较麻烦的一种。据官方文档所述,Tomcat apr需要以下三个组件的支持:

  • APR library[APR库]
  • JNI wrappers for APR used by Tomcat (libtcnative)[简单地说,如果是在Windows操作系统上,就是一个名为tcnative-1.dll的动态链接库文件]
  • OpenSSL libraries[OpenSSL库]

此外,与配置nio运行模式一样,也需要将对应的Connector节点的protocol属性值改为org.apache.coyote.http11.Http11AprProtocol。 不过,上述繁琐的操作都是Tomcat 7.0.30之前的版本才需要这样配置,从Tomcat 7.0.30版本开始,Tomcat已经自带了tcnative-1.dll等文件,并且默认就是在Tomcat apr模式下运行,因此我们只需要下载最新版本的Tomcat直接使用即可。tomcat-status-apr

此外,即使不使用Tomcat Manager,我们也可以区分出Tomcat当前的运行模式。如果以不同的Connector模式启动,在Tomcat的启动日志信息中一般会包含类似如下的不同内容,我们只需要根据这些信息即可判断出当前Tomcat的运行模式:

bio
信息: Starting ProtocolHandler ["http-bio-8080"] 2013-8-6 16:17:50 org.apache.coyote.AbstractProtocol start
nio
信息: Starting ProtocolHandler ["http-nio-8080"] 2013-8-6 16:59:53 org.apache.coyote.AbstractProtocol start
apr
信息: Starting ProtocolHandler ["http-apr-8080"] 2013-8-6 17:03:07 org.apache.coyote.AbstractProtocol start
Tomcat 6.x版本从6.0.32开始就默认支持apr。
Tomcat 7.x版本从7.0.30开始就默认支持apr。
因此,如果读者使用的Tomcat版本比较陈旧的话,强烈建议升级到最新的稳定版本。

参考链接


修改Tomcat Connector运行模式,优化Tomcat运行性能

Ubuntu 12.04查看Tomcat版本号

Tomcat本身提供了查看版本的脚本命令:version
就在Tomcat的安装目录的bin子目录下,有两个文件:
· version.bat -- Windows下的批处理脚本
· version.sh -- Linux下的Shell脚本

Ubuntu 12.04查看Tomcat版本号的命令为:

$ cd /usr/share/tomcat7/bin

$ ./version.sh

输出的信息如下:

Using CATALINA_BASE:   /usr/share/tomcat7
Using CATALINA_HOME:   /usr/share/tomcat7
Using CATALINA_TMPDIR: /usr/share/tomcat7/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar
Server version: Apache Tomcat/7.0.26
Server built:   Apr 1 2013 08:32:04
Server number:  7.0.26.0
OS Name:        Linux
OS Version:     3.2.0-58-generic
Architecture:   amd64
JVM Version:    1.7.0_91-b02
JVM Vendor:     Oracle Corporation

Eclipse Kepler Tomcat 7 调试时候 Server Tomcat v7.0 Server at localhost failed to start

Eclipse 调试 Tomcat7 下的项目,中间手工删除了某些文件,然后继续调试就报告如下错误

Server Tomcat v7.0 Server at localhost failed to start 
... 
Could not delete XXX. May be locked by another process.

删除Server,重建之后,问题依旧,重启机器,问题仍然不能解决。看来是在Eclipse 的配置文件中记录了之前的文件,而这些文件又已经被我手工删除过了,导致删除失败 。因此,只要删除这些记录文件就可以了。

删除如下文件

<workspace-directory>\.metadata\.plugins\org.eclipse.wst.server.core

重启 eclipse 重建Server,一切正常。

Tomcat7 JSP Ajax 提交中文乱码

在JS文件中存在中文,在调用 Ajax 提交数据的时候,中文总是乱码,在调用 JS的时候也已经指定了JS的编码为

<script type="text/javascript" src="./js/index/worklist.js" charset="UTF-8"></script>

但是仍然不奏效。最后打开Tomcat的server.xml文件发现默认的配置是这样的

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" />

因为要一切都统一为UTF-8所以修改为

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

问题就解决了。

Ubuntu 13.10 Apache 2.2 通过 AJP 整合 Tomcat 7

前置条件为Apache 2.2,Tomcat 7都是通过apt-get install来安装的版本。

$ sudo apt-get install apache2

$ sudo apt-get install tomcat7

1.开启ApacheAJP协议支持,Apache 2.2已经默认在/var/lib/apache2/module目录下面包含了AJP协议模块,只要打开支持就可以了。

$ sudo a2enmod proxy_ajp

$ sudo a2enmod proxy

2.编辑VirtualHost,在Ubuntu下面这个目录在/etc/apache2/sites-available下面

可以看到default.confdefault-ssl.conf两个类似的文件,我这边的default.conf莫名的被重命名成了000-default.conf,倒也无妨。

$ sudo vim /etc/apache2/sites-available/000-default.conf

<VirtualHost *:80></VirtualHost>

之间增加

ProxyPass / ajp://127.0.0.1:8009/
ProxyPassReverse / ajp://127.0.0.1:8009/
ServerName localhost

注意,此处的8009端口,要对应下面的Tomcat 7中配置的AJP的端口。

3.修改Tomcat 7的配置文件

$ sudo vim /var/lib/tomcat7/conf/server.xml

去掉被注释掉的,如果没有则增加

<!-- Define an AJP 1.3 Connector on port 8009 -->
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

注意是增加或去掉原来的配置信息,不是修改默认的8080端口上的“HTTP 1.1”部分

另外注意,如果直接去掉注释,那么根据The AJP Connector中的介绍说明(注意address部分),如果没有指定IP地址的话,默认是绑定任意地址,这样就导致外网也可以访问这个端口。因此出于安全考虑,我们需要增加这个address的设置,并且绑定到127.0.0.1。最终结果如下:

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" address="127.0.0.1" redirectPort="8443" />

4.重启Tomcat 7Apache 2

$ sudo service apache2 restart

$ sudo service tomcat7 restart

5.验证是否成功

TomcatROOT目录(/var/lib/tomcat7/webapps)下面创建一个index.jsp里面随便写点东西即可,不需要是JSP,比如可以写 "Hello JSP"
然后访问http://127.0.0.1/index.jsp如果能正常显示出来,则代表配置成功。

6.如果重启Apache2出现:

Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName.

/etc/apache2/apache2.conf文件最后加上:

#ServerName XXX (XXX 为domain name)
ServerName localhost

7.出于安全原因,禁止外网访问Tomcat8080端口

只允许Tomcat在本地的8080端口监听即可,修改

$ sudo vim /var/lib/tomcat7/conf/server.xml

添加 address="127.0.0.1"

<Connector port="8080" address="127.0.0.1" protocol="HTTP/1.1"
   connectionTimeout="20000"
   redirectPort="8443" />

重启Tomcat7

$ sudo service tomcat7 restart

8.Apache2Tomcat进行反向代理的时候,会发生重定向问题。

配置参考
在Ubuntu 12.04 LTS上安装OpenGrok浏览Android源码
具体的Apache2的配置文件如下:"/etc/apache2/sites-available/default"

#for Tomcat 7 openGrok
ProxyPass /AndroidXRef/ ajp://127.0.0.1:8009/AndroidXRef/
ProxyPassReverse /AndroidXRef/ ajp://127.0.0.1:8009/AndroidXRef/
ServerName localhost

则在正常访问http://www.mobibrw.com/AndroidXRef的时候是正常的,但是在点击里面按钮的时候会报告404跳转错误。ProxyPass后面必须携带"/",否则就会出现404问题。

产生这个错误的原因是:Apache2进行代理的时候更改了URL路径,而Tomcat7并不知道URL发生变化了,因此没有在跳转时候携带Apache2增加的跳转地址。

解决方法是在Tomcat7的配置文件/var/lib/tomcat7/conf/server.xml中的Host字段中增加

<Context path="/AndroidXRef" docBase="source/"/>

即可。

如下所示:

<Host name="localhost"  appBase="webapps"
	unpackWARs="true" autoDeploy="true">

	<Context path="/AndroidXRef" docBase="source/"/>
 
	<!-- SingleSignOn valve, share authentication between web applications 
		Documentation at: /docs/config/valve.html --> 
	<!-- 
		<Valve className="org.apache.catalina.authenticator.SingleSignOn" /> 
	-->
	<!-- Access log processes all example. 
		Documentation at: /docs/config/valve.html 
		Note: The pattern used is equivalent to using pattern="common" --> 
	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
		prefix="localhost_access_log." suffix=".txt" 
		pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
</Host>