tomcat/Jboss启动ClassNotFoundException问题思考

遇到特别邪门的一件事,就是一个很正常的项目,tomcat启动一直报ClassNotFoundException:xxx

当然,这个问题很简单处理。其原因就是maven或者项目所需的一些jar包,没有同步到WEB-INF/lib目录下面,也就是项目压根就没跑起来,tomcat就抛出异常了。

这个问题的解决办法就是--》项目右键property-->Deployment Assembly-->add-->Java Build Path Entries -->Maven Dependencies

如此一来,就算你WEB-INF下面没有lib文件夹,实际上再打包或者启动项目的时候,也会在对应位置,把相关jar包放进去,也就不会报ClassNotFoundException了。

然而,今遇到一个奇葩的事情,就是无论怎么放,都会报找不到jar

我以为是tomcat的问题,换了个新的tomcat,换了个jboss,都不行。最后,试了下netty启动,结果成功了,高兴之余,不免思考,why?

我还是怀疑是lib里面jar包没有依赖上的问题,于是把把lib依赖删了,重启netty,还是启动成功。也就是说,netty其实是不需要lib支持的。那就更加肯定了是lib依赖问题导致ClassNotFoundException出错。

于是,maven install 一下,看了下war包里lib文件下有没有jar。有!但是没有spring 的相关jar。难怪会报找不到,本来就没有,我错怪了tomcat

那,为什么么会没有呢,项目里maven依赖里是有的,只是打包后的war里面的lib下面没有spring相关的jar包

仔细看了pom文件,明白了。

该采用的是parent继承的方式,很多必用的如spring相关,mybatis相关,servlet相关,json相关的jar其实不是放在我所启动的web支撑层,而是放在最顶层的父pom中。

而父pom中的依赖代码是这样写的:

<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${org.spring.baseline.version}</version>
				<scope>provided</scope>
			</dependency>


问题也就在provied这个单词这里,scope其实是很多人还没接触的,这个参数负责控制该Jar的活动范围,而provied则是表示:按条件提供 。


测试了一下,把一个依赖设置成该属性,则在打包后不会放在lib里面,他所期望的情景就是,你的服务器上已经有该jar包了,现在放在这里只是方便本地调试,和编写代码。但是在打包的时候,不会将该jar打包。其实这是一个很好的属性,免得很多重复的无用的jar每次都要重新打包。但,这个属性也是引发这个问题的原因。

而netty本地启动的时候是不用lib里面的jar的,所以也就没有ClassNotFoundException的问题发生。



So,问题解决,原因解决。

教训是:

以后遇到问题还是要找到本质原因,直接对着本质原因去看就好了,也省去了试来试去的时间浪费。

检查pom和不太明白的属性还是要尽早查清楚,也是一种提升,和少踩坑的前置



最后附一篇Scope 相关的属性列表

Dependency Scope 

在POM 4中,<dependency>中还引入了<scope>,它主要管理依赖的部署。目前<scope>可以使用5个值: 

    * compile,缺省值,适用于所有阶段,会随着项目一起发布。 
    * provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。 
    * runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。 
    * test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。 
    * system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。

依赖范围控制哪些依赖在哪些classpath 中可用,哪些依赖包含在一个应用中。让我们详细看一下每一种范围:
 
compile (编译范围)
 
compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath 中可用,

同时它们也会被打包。
 
provided (已提供范围)
 
provided 依赖只有在当JDK 或者一个容器已提供该依赖之后才使用。例如, 如果你开发了一个web 应用,你可能在编译

classpath 中需要可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API;这个

Servlet API JAR 由你的应用服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。它们

不是传递性的,也不会被打包。
 
runtime (运行时范围)
 
runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只

有在运行的时候才需要JDBC
 驱动实现。
 
test (测试范围)
 
test范围依赖 在一般的编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
 
system (系统范围)
 
system范围依赖与provided 类似,但是你必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地

对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个

依赖范围设置成系统范围,你必须同时提供一个 systemPath 元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或

定制的 Maven 仓库中引用依赖)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值