我有一个传统项目转换为Spring Boot,它需要一个自定义侦听器来加载配置文件,该配置文件在控制器中被引用为静态全局变量,当我将自定义侦听器添加到ServletListenerRegistrationBean
嵌入式tomcat。但是,当使用传统的war包部署项目时,自定义侦听器不起作用,并导致启动失败。
这是一个简化的演示https://github.com/xuande/spring-boot-demo
@RestController
public class ConfigController {
private Map<String, Object> configMap = ScaComponentFactory.getComponent();
@GetMapping("/properties/{key}")
public Object getConfig(@PathVariable("key") String key) {
return configMap.get(key);
}
}
public class ScaContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("start listener ...");
ScaComponentFactory.map = new HashMap<>();
ScaComponentFactory.map.put("test", "this is a demo");
}
public void contextDestroyed(ServletContextEvent sce) {
ScaComponentFactory.map.clear();
ScaComponentFactory.map = null;
}
}
public class ScaComponentFactory {
protected static Map<String, String> map = null;
public static String getComponent(String key) {
return map.get(key);
}
public static Map<String, Object> getComponent() {
return Collections.unmodifiableMap(map);
}
}
主班
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
@Bean
public ServletListenerRegistrationBean<?> scaListenerRegistrationBean() {
ServletListenerRegistrationBean<ScaContextListener> registration = new ServletListenerRegistrationBean<ScaContextListener>();
registration.setListener(new ScaContextListener());
return registration;
}
}
具有嵌入式tomcat效果很好
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
2019-07-03 17:25:20.465 INFO 379676 --- [ main] org.spring.demo.Application : Starting Application on xuande00 with PID 379676 (G:\git\spring-boot-demo\target\classes started by xuande in G:\git\spring-boot-demo)
2019-07-03 17:25:20.465 INFO 379676 --- [ main] org.spring.demo.Application : No active profile set, falling back to default profiles: default
2019-07-03 17:25:23.481 INFO 379676 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 5050 (http)
2019-07-03 17:25:23.568 INFO 379676 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-07-03 17:25:23.568 INFO 379676 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.16]
2019-07-03 17:25:23.584 INFO 379676 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_144\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/bin/server;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/bin;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/lib/amd64;D:\Program Files (x86)\NetSarang\Xshell 6\;d:\program files\graphicsmagick-1.3.30-q16;C:\Program Files\Java\jdk1.8.0_111\bin;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Windows\CCM;C:\Program Files\nodejs\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Pandoc\;D:\Program Files\apache-maven-3.5.2\bin;;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\Program Files\Microsoft VS Code\bin;D:\Program Files\Redis\;C:\Users\xuande\AppData\Local\Microsoft\WindowsApps;C:\Users\xuande\AppData\Roaming\npm;C:\Program Files (x86)\Pandoc\;D:\Program Files\hadoop-2.7.4\bin;D:\Program Files\gradle-4.6\bin;;E:\eclipse-loushang;;.]
2019-07-03 17:25:24.006 INFO 379676 --- [ main] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2019-07-03 17:25:24.006 INFO 379676 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-07-03 17:25:24.006 INFO 379676 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3447 ms
start listener ...
2019-07-03 17:25:24.428 INFO 379676 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-07-03 17:25:25.037 INFO 379676 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5050 (http) with context path ''
2019-07-03 17:25:25.075 INFO 379676 --- [ main] org.spring.demo.Application : Started Application in 5.512 seconds (JVM running for 6.3)
独立的tomcat无法正常工作
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Server version: Apache Tomcat/8.5.24
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Server built: Nov 27 2017 13:05:30 UTC
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Server number: 8.5.24.0
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: OS Name: Windows 10
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: OS Version: 10.0
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Architecture: amd64
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Java Home: C:\Program Files\Java\jdk1.8.0_144\jre
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: JVM Version: 1.8.0_144-b01
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: JVM Vendor: Oracle Corporation
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: CATALINA_BASE: G:\apache-tomcat-8.5.24
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: CATALINA_HOME: G:\apache-tomcat-8.5.24
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:8783
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -Dcatalina.base=G:\apache-tomcat-8.5.24
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -Dcatalina.home=G:\apache-tomcat-8.5.24
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -Dwtp.deploy=G:\apache-tomcat-8.5.24\wtpwebapps
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -Djava.endorsed.dirs=G:\apache-tomcat-8.5.24\endorsed
July 03, 2019 5:21:35 PM org.apache.catalina.startup.VersionLoggerListener log
Info: Command line argument: -Dfile.encoding=UTF-8
July 03, 2019 5:21:35 PM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
Info: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_144\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Java\jdk1.8.0_144\jre\bin;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/bin/server;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/bin;C:/Program Files/Java/jdk1.8.0_111/bin/../jre/lib/amd64;D:\Program Files (x86)\NetSarang\Xshell 6\;d:\program files\graphicsmagick-1.3.30-q16;C:\Program Files\Java\jdk1.8.0_111\bin;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Windows\CCM;C:\Program Files\nodejs\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Pandoc\;D:\Program Files\apache-maven-3.5.2\bin;;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\Program Files\Microsoft VS Code\bin;D:\Program Files\Redis\;C:\Users\xuande\AppData\Local\Microsoft\WindowsApps;C:\Users\xuande\AppData\Roaming\npm;C:\Program Files (x86)\Pandoc\;D:\Program Files\hadoop-2.7.4\bin;D:\Program Files\gradle-4.6\bin;;E:\eclipse-loushang;;.]
July 03, 2019 5:21:35 PM org.apache.coyote.AbstractProtocol init
Info: Initializing ProtocolHandler ["http-nio-9080"]
July 03, 2019 5:21:36 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
Info: Using a shared selector for servlet write/read
July 03, 2019 5:21:36 PM org.apache.coyote.AbstractProtocol init
Info: Initializing ProtocolHandler ["ajp-nio-9019"]
July 03, 2019 5:21:36 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
Info: Using a shared selector for servlet write/read
July 03, 2019 5:21:36 PM org.apache.catalina.startup.Catalina load
Info: Initialization processed in 1660 ms
July 03, 2019 5:21:36 PM org.apache.catalina.core.StandardService startInternal
Info: Starting service [Catalina]
July 03, 2019 5:21:36 PM org.apache.catalina.core.StandardEngine startInternal
Info: Starting Servlet Engine: Apache Tomcat/8.5.24
July 03, 2019 5:21:42 PM org.apache.jasper.servlet.TldScanner scanJars
Info: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
July 03, 2019 5:21:43 PM org.apache.catalina.core.ApplicationContext log
Info: 2 Spring WebApplicationInitializers detected on classpath
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
2019-07-03 17:21:44.556 INFO 398420 --- [ost-startStop-1] org.spring.demo.Application : Starting Application on xuande00 with PID 398420 (G:\git\spring-boot-demo\target\demo\WEB-INF\classes started by xuande in E:\eclipse-loushang)
2019-07-03 17:21:44.556 INFO 398420 --- [ost-startStop-1] org.spring.demo.Application : No active profile set, falling back to default profiles: default
2019-07-03 17:21:46.041 INFO 398420 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/demo] : Initializing Spring embedded WebApplicationContext
2019-07-03 17:21:46.056 INFO 398420 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1422 ms
2019-07-03 17:21:46.667 WARN 398420 --- [ost-startStop-1] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configController' defined in file [G:\git\spring-boot-demo\target\demo\WEB-INF\classes\org\spring\demo\controller\ConfigController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.spring.demo.controller.ConfigController]: Constructor threw exception; nested exception is java.lang.NullPointerException
2019-07-03 17:21:46.683 INFO 398420 --- [ost-startStop-1] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-07-03 17:21:46.699 ERROR 398420 --- [ost-startStop-1] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configController' defined in file [G:\git\spring-boot-demo\target\demo\WEB-INF\classes\org\spring\demo\controller\ConfigController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.spring.demo.controller.ConfigController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1287) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:157) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:137) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:171) [spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196) [catalina.jar:8.5.24]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:8.5.24]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419) [catalina.jar:8.5.24]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409) [catalina.jar:8.5.24]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.spring.demo.controller.ConfigController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1279) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
... 26 common frames omitted
Caused by: java.lang.NullPointerException: null
at java.util.Collections$UnmodifiableMap.<init>(Collections.java:1446) ~[na:1.8.0_144]
at java.util.Collections.unmodifiableMap(Collections.java:1433) ~[na:1.8.0_144]
at org.spring.demo.listener.ScaComponentFactory.getComponent(ScaComponentFactory.java:15) ~[classes/:na]
at org.spring.demo.controller.ConfigController.<init>(ConfigController.java:13) ~[classes/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_144]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_144]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_144]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_144]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
... 28 common frames omitted
答案 0 :(得分:0)
@Configuration
public class ScaContextInitializer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("start listener ...");
ScaComponentFactory.map = new HashMap<>();
ScaComponentFactory.map.put("test", "this is a demo");
}
}
使用ServletContextInitializer
代替ServletContextListener
,嵌入式tomcat和独立的tomcat都可以很好地工作