问题
I recently downloaded the source code for the Spring MVC (Version 4.0.2.RELEASE) module within the Spring Framework. My intention is to run against the actual source code for the module instead of the actual .jar
file. (Long story, only for testing purposes).
After downloading the source code, I removed the jar
file from my project, compiled and deployed to the server. When I hit one of the URLs handled by the dispatcher servlet I was presented with the error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0': Invocation of init method failed; nested exception is java.lang.Error: Unresolved compilation problems:
The import java.time cannot be resolved
The method toZoneId() is undefined for the type TimeZone
ZoneId cannot be resolved
After some research and digging into the source code I realized the class mentioned in the error is part of JDK/JRE 1.8. Before removing the .jar
file my project ran without issue on JDK/JRE 1.7.
My question is how does Spring include classes from JDK 1.8, yet still manage to run under JDK/JRE 1.7? Why is the exception not thrown when using Spring's .jar
file, but it is thrown when I provide the source (and the jar file is missing)?
Full Stack Trace
Mar 26, 2014 7:27:18 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Allocate exception for servlet dispatcher
java.lang.Error: Unresolved compilation problems:
The import java.time cannot be resolved
The method toZoneId() is undefined for the type TimeZone
ZoneId cannot be resolved
at org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver.<init>(ServletRequestMethodArgumentResolver.java:23)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getDefaultArgumentResolvers(RequestMappingHandlerAdapter.java:522)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.afterPropertiesSet(RequestMappingHandlerAdapter.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:672)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:543)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1274)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1186)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:858)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:136)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
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:744)
回答1:
The answer to the headline question is: Spring builds with Java 8, but is compatible with Java 7 (and 6).
ServletRequestMethodArgumentResolver
does import java.time.ZoneId
, but it only refers to that class in a nested class which isn't instantiated unless Java 8 is on the classpath. There are many examples like this in Spring source code (always have been, e.g. since it started supporting Java 5).
来源:https://stackoverflow.com/questions/22659866/how-does-spring-use-java-8-classes-yet-it-runs-on-java-7