1. 程式人生 > >Maven部署過程中的ClassCastException問題

Maven部署過程中的ClassCastException問題

引言: Maven功能強大,但是又有些複雜,難以捉摸和使用。在本人開發中碰到了一個ClassCastException的問題,通過這個問題的解決,加深了對於maven依賴管理中scope的理解。

1. 問題的引入

   部署環境tomcat 7, 開發中使用的框架spring,spring data,hibernate之類的,基於Maven部署過程中,會出現以下異常資訊:

SEVERE: Exception starting filter Spring OpenEntityManagerInViewFilter
java.lang.ClassCastException: org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter cannot be cast to javax.servlet.Filter
	at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
	at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
	at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
	at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4001)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4651)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
	at org.apache.catalina.startup.Embedded.start(Embedded.java:825)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.startContainer(AbstractRunMojo.java:558)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.execute(AbstractRunMojo.java:255)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Feb 3, 2015 1:36:32 PM org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter Set Character Encoding
java.lang.ClassCastException: org.springframework.web.filter.CharacterEncodingFilter cannot be cast to javax.servlet.Filter
	at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
	at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
	at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
	at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4001)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4651)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
	at org.apache.catalina.startup.Embedded.start(Embedded.java:825)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.startContainer(AbstractRunMojo.java:558)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.execute(AbstractRunMojo.java:255)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Feb 3, 2015 1:36:32 PM org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter HiddenHttpMethodFilter
java.lang.ClassCastException: org.springframework.web.filter.HiddenHttpMethodFilter cannot be cast to javax.servlet.Filter
	at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
	at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
	at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
	at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4001)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4651)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
	at org.apache.catalina.startup.Embedded.start(Embedded.java:825)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.startContainer(AbstractRunMojo.java:558)
	at org.codehaus.mojo.tomcat.AbstractRunMojo.execute(AbstractRunMojo.java:255)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Feb 3, 2015 1:36:32 PM org.apache.catalina.core.StandardContext start
SEVERE: Error filterStart
Feb 3, 2015 1:36:32 PM org.apache.catalina.core.StandardContext start
SEVERE: Context [/bsettle] startup failed due to previous errors

2. 問題分析

   這幾個Servlet都是在web.xml中配置的Filter,其配置沒有問題。錯誤型別為ClassCastException, 就是其實現的Filter與目標的Filter存在不同,就是說有可能是類庫引用的不同,導致在啟動過程中,出現這樣的問題。

3. 檢視pom.xml

  在開發中,引入瞭如下包,用以解決Servlet/JSP中常用類庫的引用問題,這些都是在Web伺服器中實現的類庫。

		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-servlet-api</artifactId>
			<version>7.0.56</version>
		</dependency>

		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jsp-api</artifactId>
			<version>7.0.57</version>			
		</dependency>
  這裡可以看到,jsp/servlet將在整個的打包部署宣告週期中被用到,並被打包到部署環境中。

4. 問題的解決

     由於無法預知最終部署的Web伺服器的版本和型別,故這裡的這兩個依賴在編譯、測試中會用到,但是在部署環境中,是不能打包到部署環境中去的。

     故需要做如下修改:

               <dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-servlet-api</artifactId>
			<version>7.0.56</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jsp-api</artifactId>
			<version>7.0.57</version>			
			<scope>provided</scope>
		</dependency>

  5. Scope的含義和使用

   <dependency>中<scope>,它主要管理依賴的部署。目前<scope>可以使用5個值: 
    * compile,預設值,適用於所有階段,會隨著專案一起釋出。 
    * provided,類似compile,期望JDK、容器或使用者會提供這個依賴。如servlet.jar。 
    * runtime,只在執行時使用,如JDBC驅動,適用執行和測試階段。 
    * test,只在測試時使用,用於編譯和執行測試程式碼。不會隨專案釋出。 
    * system,類似provided,需要顯式提供包含依賴的jar,Maven不會在Repository中查詢它。

依賴範圍(scope) 主原始碼classpath可用 測試原始碼classpath可用 會被打包
compile 預設值 TRUE TRUE TRUE
test FALSE TRUE FALSE
runtime FALSE TRUE TRUE
provided TRUE TRUE FALSE