因为某个Bean为空,无法启动Spring Boot应用
我在让一个应用程序运行时遇到了问题。
我正在使用Spring 5来运行一个使用SOAP的 Spring Boot应用。它运行在Java 17上。它在启动时就退出,因为在创建一个类时发生了空指针异常(NullPointerException)而导致“无法创建类”的错误:``` org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'soapCategoryService' defined in file [C:\Development\sap.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\sapauthorize\WEB-INF\classes\ll\sapauthorization\services\soap\SoapCategoryService.class]: Invocation of init method failed; nested exception is java.lang.NullPointerException: Cannot invoke "javax.xml.soap.MessageFactory.createMessage()" because "this.messageFactory" is null at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:920) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.27.jar:5.3.27]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97) ~[spring-boot-2.7.11.jar:2.7.11]
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174) ~[spring-web-5.3.27.jar:5.3.27]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4479) ~[catalina.jar:9.0.113]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1201) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1191) ~[catalina.jar:9.0.113]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:82) ~[tomcat-util.jar:9.0.113]
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:747) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:726) ~[catalina.jar:9.0.113]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1201) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1191) ~[catalina.jar:9.0.113]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:82) ~[tomcat-util.jar:9.0.113]
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) ~[na:na]
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:747) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:209) ~[catalina.jar:9.0.113]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:410) ~[catalina.jar:9.0.113]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ~[catalina.jar:9.0.113]
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:872) ~[catalina.jar:9.0.113]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) ~[catalina.jar:9.0.113]
at org.apache.catalina.startup.Catalina.start(Catalina.java:736) ~[catalina.jar:9.0.113]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na]
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342) ~[bootstrap.jar:9.0.113]
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473) ~[bootstrap.jar:9.0.113]
Caused by: java.lang.NullPointerException: Cannot invoke "javax.xml.soap.MessageFactory.createMessage()" because "this.messageFactory" is null
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:167) ~[spring-ws-core-3.1.6.jar:na]
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:61) ~[spring-ws-core-3.1.6.jar:na]
at org.springframework.ws.context.DefaultMessageContext.
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:536) ~[spring-ws-core-3.1.6.jar:na]
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:523) ~[spring-ws-core-3.1.6.jar:na]
at ll.sapauthorization.services.soap.SoapService.sendAndReceive(SoapService.java:63) ~[classes/:2.0]
at ll.sapauthorization.services.soap.SoapCategoryService.populateCache(SoapCategoryService.java:153) ~[classes/:2.0]
at ll.sapauthorization.services.soap.SoapCategoryService.afterPropertiesSet(SoapCategoryService.java:85) ~[classes/:2.0]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.27.jar:5.3.27]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.27.jar:5.3.27]
... 46 common frames omitted
我知道问题所在:在应用启动时,SoapCategoryService 类使用的消息工厂没有被创建。我已经尝试使用 @Autowired 注解来创建消息工厂,但这并未解决问题。显然,MessageFactory 对象是在一个名为 SaajSoapMessageFactory 的类中创建的——这是一个我无法修改的 Spring 框架类!因此,我无法将带有 @Autowired 的 MessageFactory 对象添加到它中,从而也无法让 MessageFactory 被创建。
有人有办法解决这个问题吗?之前有人遇到过吗?如果遇到过,你是如何解决的(如果你确实解决了的话)?
注:给关闭我问题的那位:
1. 链接 [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) 并没有解决我的问题,因为我不是在问“为什么会抛出 NullPointerException”。我知道 NullPointerException 是什么,以及应该怎么修复。问题在于,当修复需要在一个我无法编辑的 .jar 库中的代码里进行时,如何做到!正如我所说:自动装配显然必须在名为 SaajSoapMessageFactory 的类中完成——它是 Spring Framework 的一部分。我真正需要的不是关于 NullPointerExceptions 的基础信息,而是知道在我无法编辑(且不修改 Spring Framework)的类中需要自动装配时,如何避免被自动装配的类为 null。
2. 请注意,由于空指针异常是在 Spring 框架内部抛出的,原因是在需要在 Spring 框架类中完成自动装配的情况下,相关代码是 SaajSoapMessageFactory 类,它属于 Spring Framework 的开发者。
3. 另外,请注意,如我所述,我确实尝试对 MessageFactory 类进行自动装配。为此,我必须在名为 SSConfig.java 的类中创建一个 bean,如下所示:
@Configuration public class SSConfig { . . . @Bean public MessageFactory messageFactory() throws SOAPException { return(MessageFactory.newInstance()); } } ```
这使得你链接中的答案 Why is my Spring @Autowired field null? 不再适用。如果我没有尝试过这个,我就不会来问这个问题。
解决方案
你的错误信息写着 Caused by: java.lang.NullPointerException: Cannot invoke "javax.xml.soap.MessageFactory.createMessage()" because "this.messageFactory" is null。
正如 这条StackOverflow回答 所说,SAAJ (javax.xml.soap.*) 已在Java 11中从JDK中移除了。
你可以尝试在项目中添加 javax.xml.soap 依赖,但我不知道这是否能按预期工作。如果可以,你应该迁移到Spring Web Services 5.x(https://docs.spring.io/spring-ws/docs/current/reference/html/)
或者,(前提是你的项目中已有 javax.xml.soap 依赖),如评论中的 @George Lvov所述,你可以使用 这个回答 的示例来创建一个托管的bean。