【发布时间】:2016-02-14 12:20:00
【问题描述】:
Spring Boot (1.2.7) Web 应用(响应 SSL 请求)在 Intellij IDEA 上运行效果很好。
构建 JAR 工件以从命令行运行,启动时抛出错误
org.springframework.context.ApplicationContextException:
Unable to start embedded container;
nested exception isorg.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
问题
- 如何避免此错误?
- 如果我需要声明一个 EmbeddedServletContainerFactory,如何让其 ServletContainer 处理对我的 Controller 的请求?
尝试的解决方案
按错误请求添加 EmbeddedservletContainerFactory。项目现在从 JAR 启动,但控制器没有像从 IntelliJ 运行时那样接收请求。
这是我的 Application.class 添加 EmbeddedServletContainerFactory
后的样子package org.coursera.diabetes;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import diabetes.common.model.*;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@SpringBootApplication
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
private static final String dbUrl = "jdbc:h2:mem:testdb";
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
@Profile("production")
public EmbeddedServletContainerFactory servletContainer(@Value("${keystore.file}") Resource keystoreFile) {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
//factory.setPort(8443);
String absoluteKeystoreFile = "";
try {
absoluteKeystoreFile = keystoreFile.getFile().getAbsolutePath();
logger.info(String.format("******** keystore: %s", absoluteKeystoreFile));
} catch (IOException e) {
e.printStackTrace();
}
tomcat.addAdditionalTomcatConnectors(createSslConnector(absoluteKeystoreFile));
return tomcat;
}
private Connector createSslConnector(String absKeystoreFile) {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(absKeystoreFile);
protocol.setKeystorePass("changeit");
protocol.setKeyAlias("tomcat");
return connector;
}
catch (Exception ex) {
throw new IllegalStateException("can't access keystore: [" + "keystore"
+ "] or truststore: [" + "keystore" + "]", ex);
}
}
}
注意事项
Spring Boot (web) 应用程序在 Intellij IDEA 中运行良好,响应 https 请求,无需在 application.properties 中添加几行代码:
security.require-ssl=true
server.port=8443
server.ssl.key-store=src/main/resources/private/keystore
server.ssl.key-store-password=changeit
server.ssl.key-password=changeit
要从命令行启动 JAR 工件,我使用:
java -Dspring.profiles.active=production -Dkeystore.file=file:///$PWD/keystore -jar diabetes-spring.jar
JAR 启动时不会出错,但 https 网络请求(从 Intellij 工作)只是返回 Apache/tomcat 404 “请求的资源不可用”。
编辑
使用 -Ddebug 运行 JAR 会输出以下信息(我省略了所有 DEBUG 消息,因为找不到配置文件 application.properties / application/application-production.properties 似乎不合适)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2015-11-13 14:16:39.980 INFO 47600 --- [ main] org.coursera.diabetes.Applica
tion : Starting Application on Bakers-MacBook-Pro.local with PID 47600 (/User
s/baker/coursera-android/MoCCA-15/spring-tests/diabetes_root2/diabetes-spring/out/artifa
cts/diabetes_spring_jar/diabetes-spring.jar started by blam in /Users/blam/coursera-and
roid/MoCCA-15/spring-tests/diabetes_root2/diabetes-spring/out/artifacts/diabetes_spring
_jar)
2015-11-13 14:16:39.983 DEBUG 47600 --- [ main] o.s.boot.SpringApplication
: Loading source class org.coursera.diabetes.Application
2015-11-13 14:16:40.011 DEBUG 47600 --- [ main] o.s.b.c.c.ConfigFileApplicati
onListener : Activated profiles production
2015-11-13 14:16:40.011 DEBUG 47600 --- [ main] o.s.b.c.c.ConfigFileApplicati
onListener : Loaded config file 'file:./config/application.properties'
2015-11-13 14:16:40.020 INFO 47600 --- [ main] ationConfigEmbeddedWebApplica
tionContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbe
ddedWebApplicationContext@23faf8f2: startup date [Fri Nov 13 14:16:40 WET 2015]; root o
f context hierarchy
2015-11-13 14:16:40.022 DEBUG 47600 --- [ main] ationConfigEmbeddedWebApplica
tionContext : Bean factory for org.springframework.boot.context.embedded.AnnotationConf
igEmbeddedWebApplicationContext@23faf8f2: org.springframework.beans.factory.support.Def
aultListableBeanFactory@6cc7b4de: defining beans [org.springframework.context.annotatio
n.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.inter
nalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequired
AnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProc
essor,application]; root of factory hierarchy
2015-11-13 14:16:40.220 DEBUG 47600 --- [ main] ationConfigEmbeddedWebApplica
tionContext : Unable to locate MessageSource with name 'messageSource': using default [
org.springframework.context.support.DelegatingMessageSource@20ce78ec]
2015-11-13 14:16:40.221 DEBUG 47600 --- [ main] ationConfigEmbeddedWebApplica
tionContext : Using ApplicationEventMulticaster [org.springframework.context.event.Simp
leApplicationEventMulticaster@393671df]
2015-11-13 14:16:40.226 WARN 47600 --- [ main] ationConfigEmbeddedWebApplica
tionContext : Exception encountered during context initialization - cancelling refresh
attempt
org.springframework.context.ApplicationContextException: Unable to start embedded conta
iner; nested exception is org.springframework.context.ApplicationContextException: Unab
le to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactor
y bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRe
fresh(EmbeddedWebApplicationContext.java:132)
at org.springframework.context.support.AbstractApplicationContext.refresh(Abstr
actApplicationContext.java:474)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refr
esh(EmbeddedWebApplicationContext.java:117)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:68
9)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:969)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:958)
at org.coursera.diabetes.Application.main(Application.java:40)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:182)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:155)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:129)
... 7 common frames omitted
2015-11-13 14:16:40.227 INFO 47600 --- [ main] .b.l.ClasspathLoggingApplicationListener : Application failed to start with classpath: [file:/Users/baker/coursera-android/MoCCA-15/spring-tests/diabetes_root2/diabetes-spring/out/artifacts/diabetes_spring_jar/diabetes-spring.jar]
2015-11-13 14:16:40.228 ERROR 47600 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:117)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:689)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:969)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:958)
at org.coursera.diabetes.Application.main(Application.java:40)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:182)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:155)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:129)
... 7 common frames omitted
【问题讨论】:
-
尝试恢复原状并查看自动配置报告(使用 --debug 运行)以了解嵌入式 servlet 容器未自动配置的原因
-
@AndyWilkinson 谢谢。尝试了 -Ddebug 选项。奇怪的是,在运行 JAR 时没有生成自动配置报告。 (上面复制的输出。)。在 IDEA 中运行 --debug,报告按预期生成。我想知道在构建 JAR 工件时是否以某种方式关闭了自动配置。
-
你如何构建jar?
-
在 IDEA -> Project Structure (Cmd + ;) -> Artifacts -> + button, -> JAR -> from Modules with Dependencies -> 选择主模块 -> 选择主类 -> JAR 文件从库中:解压缩到目标 JAR -> META-INF/MANIFEST.MF 的目录:
/src/main/resources/ -> 构建(在菜单中)-> 构建工件 -> [选择 jar 名称] - > 构建
标签: java spring spring-boot