我有一个使用Gucie-Servlet框架编写、由Maven 3构建的Java Web应用程序。当我将其部署到Tomcat 7容器并尝试通过浏览器访问时,Tomcat会返回404状态码。以下是来自Tomcat的日志:
Apr 4, 2013 11:39:50 AM org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextDestroyed()
Apr 4, 2013 11:39:50 AM org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextDestroyed()
Apr 4, 2013 11:39:55 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class ru.hive.webserver.config.HiveServletConfig
java.lang.NoClassDefFoundError: ru/hive/base/db/modules/DatabaseModule
at ru.hive.webserver.config.HiveServletConfig.getInjector(HiveServletConfig.java:24)
at com.google.inject.servlet.GuiceServletContextListener.contextInitialized(GuiceServletContextListener.java:45)
at ru.hive.webserver.config.HiveServletConfig.contextInitialized(HiveServletConfig.java:19)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5291)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:977)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1655)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: ru.hive.base.db.modules.DatabaseModule
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1713)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1558)
... 17 more
Apr 4, 2013 11:39:55 AM org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
Apr 4, 2013 11:39:55 AM org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
Apr 4, 2013 11:39:55 AM org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: attributeAdded('org.apache.jasper.compiler.TldLocationsCache', 'org.apache.jasper.compiler.TldLocationsCache@e8606c')
异常表示我的应用程序的 CLASSPATH 中没有名为 ru.hive.base.db.modules.DatabaseModule 的类,但事实并非如此:
frodo@shire:~/apache-tomcat-7.0.37/webapps/hive/WEB-INF/lib$ ls -l
total 30132
-rw-rw-r-- 1 frodo frodo 4467 нояб. 22 13:46 aopalliance-1.0.jar
-rw-rw-r-- 1 frodo frodo 27010023 апр. 4 11:39 base-0.0.42-SNAPSHOT.jar
-rw-rw-r-- 1 frodo frodo 232019 дек. 18 10:12 commons-beanutils-1.8.3.jar
-rw-rw-r-- 1 frodo frodo 58160 авг. 2 2011 commons-codec-1.4.jar
-rw-rw-r-- 1 frodo frodo 196768 дек. 18 10:12 commons-digester-2.1.jar
-rw-rw-r-- 1 frodo frodo 163151 нояб. 22 13:46 commons-io-2.1.jar
-rw-rw-r-- 1 frodo frodo 60686 авг. 2 2011 commons-logging-1.1.1.jar
-rw-rw-r-- 1 frodo frodo 189285 нояб. 28 15:01 gson-2.2.2.jar
-rw-rw-r-- 1 frodo frodo 710492 февр. 6 18:59 guice-3.0.jar
-rw-rw-r-- 1 frodo frodo 65012 февр. 13 13:21 guice-servlet-3.0.jar
-rw-rw-r-- 1 frodo frodo 352585 нояб. 22 13:46 httpclient-4.1.3.jar
-rw-rw-r-- 1 frodo frodo 181410 нояб. 22 13:46 httpcore-4.1.4.jar
-rw-rw-r-- 1 frodo frodo 26938 нояб. 22 13:46 httpmime-4.1.3.jar
-rw-rw-r-- 1 frodo frodo 2497 февр. 6 18:59 javax.inject-1.jar
-rw-rw-r-- 1 frodo frodo 31866 февр. 6 18:59 jsr305-2.0.1.jar
-rw-rw-r-- 1 frodo frodo 25962 нояб. 22 13:46 slf4j-api-1.6.4.jar
-rw-rw-r-- 1 frodo frodo 371816 нояб. 22 13:46 solr-solrj-4.0.0.jar
-rw-rw-r-- 1 frodo frodo 520969 нояб. 22 13:46 wstx-asl-3.2.7.jar
-rw-rw-r-- 1 frodo frodo 608239 нояб. 22 13:46 zookeeper-3.3.6.jar
JAR base-0.0.42-SNAPSHOT.jar包含一个Tomcat找不到的类。JAR内部的目录结构与堆栈跟踪中完整类名相同。我的项目的pom.xml如下:
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>webserver</artifactId>
<version>0.0.42-SNAPSHOT</version>
<packaging>war</packaging>
<name>Api servlet</name>
<parent>
<groupId>ru.hive</groupId>
<artifactId>main</artifactId>
<version>0.0.41-SNAPSHOT</version>
<relativePath>../main</relativePath>
</parent>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<solr.url>http://localhost:8983/solr</solr.url>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<server>local_tomcat</server>
<url>http://192.168.0.39:8080/manager/text</url>
<path>/hive</path>
<update>true</update>
<username>user</username>
<password>pass</password>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>production</id>
<properties>
<solr.url>http://localhost:8983/solr/hive</solr.url>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<server>production_tomcat</server>
<url>http://some.ip.address:8080/manager/text</url>
<path>/hive</path>
<update>true</update>
<username>user</username>
<password>pass</password>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>ru.hive</groupId>
<artifactId>base</artifactId>
<version>0.0.42-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Maven Repository Switchboard</name>
<url>http://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>repo</id>
<releases>
<enabled>true</enabled>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>file://${project.basedir}/lib</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<build>
<finalName>hive</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<directory>target</directory>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
<webResources>
<webResource>
<directory>src/main/webapp/META-INF</directory>
<includes>
<include>context.xml</include>
</includes>
<filtering>true</filtering>
<targetPath>META-INF</targetPath>
</webResource>
</webResources>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>default-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>default-install</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>default-resources</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
<execution>
<id>default-testResources</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<executions>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<reporting>
<outputDirectory>target/site</outputDirectory>
</reporting>
</project>
那么问题是我做错了什么,为什么会出现ClassDefNotFound异常?
PS. maven-war-plugin配置的编辑版本:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
<configuration>
<webResources>
<webResource>
<directory>src/main/webapp/META-INF</directory>
<includes>
<include>context.xml</include>
</includes>
<filtering>true</filtering>
<targetPath>META-INF</targetPath>
</webResource>
</webResources>
</configuration>
</plugin>
附录. ru.hive.webserver.config.HiveServletConfig 类的清单
package ru.hive.webserver.config;
import javax.servlet.ServletContextEvent;
import ru.hive.base.db.modules.DatabaseModule;
import ru.hive.base.state.modules.StateManagerModule;
import ru.hive.webserver.api.ApiServlet;
import ru.hive.webserver.scheduler.Scheduler;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
public class HiveServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
install(new DatabaseModule());
install(new StateManagerModule());
serve("/api").with(ApiServlet.class);
serve("/scheduler").with(Scheduler.class);
}
});
}
}
PPPS. <TOMCAT_HOME>/lib
中的 JAR 列表:
`-rw-r--r-- 1 jcdenton jcdenton 15264 марта 22 18:38 annotations-api.jar
-rw-r--r-- 1 jcdenton jcdenton 54176 марта 22 18:38 catalina-ant.jar
-rw-r--r-- 1 jcdenton jcdenton 132729 марта 22 18:38 catalina-ha.jar
-rw-r--r-- 1 jcdenton jcdenton 1563926 марта 22 18:38 catalina.jar
-rw-r--r-- 1 jcdenton jcdenton 255182 марта 22 18:38 catalina-tribes.jar
-rw-r--r-- 1 jcdenton jcdenton 1796326 марта 22 18:38 ecj-4.2.1.jar
-rw-r--r-- 1 jcdenton jcdenton 46085 марта 22 18:38 el-api.jar
-rw-r--r-- 1 jcdenton jcdenton 123241 марта 22 18:38 jasper-el.jar
-rw-r--r-- 1 jcdenton jcdenton 599131 марта 22 18:38 jasper.jar
-rw-r--r-- 1 jcdenton jcdenton 88690 марта 22 18:38 jsp-api.jar
-rw-r--r-- 1 jcdenton jcdenton 177599 марта 22 18:38 servlet-api.jar
-rw-r--r-- 1 jcdenton jcdenton 6873 марта 22 18:38 tomcat-api.jar
-rw-r--r-- 1 jcdenton jcdenton 795308 марта 22 18:38 tomcat-coyote.jar
-rw-r--r-- 1 jcdenton jcdenton 235411 марта 22 18:38 tomcat-dbcp.jar
-rw-r--r-- 1 jcdenton jcdenton 77364 марта 22 18:38 tomcat-i18n-es.jar
-rw-r--r-- 1 jcdenton jcdenton 48693 марта 22 18:38 tomcat-i18n-fr.jar
-rw-r--r-- 1 jcdenton jcdenton 51678 марта 22 18:38 tomcat-i18n-ja.jar
-rw-r--r-- 1 jcdenton jcdenton 123958 марта 22 18:38 tomcat-jdbc.jar
-rw-r--r-- 1 jcdenton jcdenton 23174 марта 22 18:38 tomcat-util.jar`
WEB-INF/classes
目录中,而不是外部 JAR。它为我用于依赖注入的 Guice-Servlet 框架提供配置。 - Fyodor Sherstobitov