Spring Boot JAR - 缺少 EmbeddedServletContainerFactory [英] Spring Boot JAR - missing EmbeddedServletContainerFactory

查看:64
本文介绍了Spring Boot JAR - 缺少 EmbeddedServletContainerFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spring Boot (1.2.7) Web 应用(响应 SSL 请求)在 Intellij IDEA 中运行良好.

Spring Boot (1.2.7) web app (responds to SSL requests) works great running from Intellij IDEA.

构建 JAR 工件以从命令行运行,启动时抛出错误

Build JAR artifact to run from command line, throws error upon start

org.springframework.context.ApplicationContextException:无法启动嵌入式容器;嵌套异常是 org.springframework.context.ApplicationContextException:由于缺少EmbeddedServletContainerFactory bean,无法启动EmbeddedWebApplicationContext.

  1. 如何避免此错误?
  2. 如果我需要声明一个 EmbeddedServletContainerFactory,我如何让它的 ServletContainer 处理我的控制器的请求?

尝试过的解决方案

根据错误的要求添加了 EmbeddedservletContainerFactory.项目现在从 JAR 开始,但控制器没有像从 IntelliJ 运行时那样接收请求.

Solutions Tried

Added EmbeddedservletContainerFactory as requested by error. Project now starts from JAR, but requests are not being received by Controller like it does when running from IntelliJ.

这是我的 Application.class 添加 EmbeddedServletContainerFactory 之后的样子

Here's what my Application.class looks like after adding the 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 中做任何额外的事情:

Notes

Spring Boot (web) application works great running from Intellij IDEA, responding to https requests without needing to do anything more than a few additional lines in 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 工件,我使用:

To start JAR artifact from command line I use:

java -Dspring.profiles.active=production -Dkeystore.file=file:///$PWD/keystore -jar diabetes-spring.jar

JAR 启动时没有错误,但 https 网络请求(从 Intellij 工作)只是返回 Apache/tomcat 404请求的资源不可用".

JAR starts without error doing this, but https web requests (which work from Intellij) simply return Apache/tomcat 404 "The requested resource is not available".

使用 -Ddebug 运行 JAR 输出以下信息(我省略了所有调试消息,因为找不到配置文件 application.properties/application/application-production.properties 似乎不相关)

Running the JAR with -Ddebug outputs the following information (I'm omitting all the DEBUG messages for not finding config files application.properties / application / application-production.properties which don't seem pertitenent)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: 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

推荐答案

在 IntelliJ IDEA - Project Structure - Artifacts - Available Elements 中,所有 Gradle 依赖库都需要提取到输出根目录以供一个 Spring Boot 应用程序的 JAR,以便从 java 命令行执行正常运行.

In IntelliJ IDEA - Project Structure - Artifacts - Available Elements, all the Gradle dependency libraries need to be Extracted into Output Root for the JAR of a Spring Boot application to run properly from java command line execution.

将 JAR 工件更改为此后,我可以构建 JAR 并从命令行 JVM 运行它.

After changing the JAR artifact to this, I could Build the JAR and run it from the command line JVM.

对于在 HTTPS/SSL 端口 8443 上运行的默认 TomcatEmbeddedServletContainerFactory,请指定与 application.properties 中所需内容等效的 java 命令行参数.

For the default TomcatEmbeddedServletContainerFactory to run on HTTPS/SSL port 8443 specify java command line arguments equivalent to what is required in application.properties.

java -jar your-spring.jar --security.require-ssl=true --server.port=8443 --server.ssl.key-store=keystore --server.ssl.key-store-password=changeit --server.ssl.key-password=changeit

这篇关于Spring Boot JAR - 缺少 EmbeddedServletContainerFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆