如何使用WebApplicationInitializer迁移现有的Spring mvc应用程序 - >使用“自下而上”方法的Spring-boot-web-starter没有@EnableAutoConfig

时间:2016-01-02 11:30:38

标签: spring-boot

所以我试图将spring mvc(sp4)应用程序迁移到spring-boot应用程序但是我想采用“自下而上”的方法,因为我已经制作/测试了我的配置文件,我知道它们工作我只是想要转换为准系统spring-boot-web应用程序,其中我现有的配置将在嵌入式tomcat服务器上工作。

我到目前为止在文档中阅读的所有解决方案采用“自上而下”的方法,他们建议导入您需要的所有起始罐,并@EnableAutoConfiguration和“关闭”您不需要的配置时间。我认为如果您从头开始,这种“自上而下”的方法很有效,但如果您要迁移现有的应用程序则不行。

问题:据说我正在尝试通过“自下而上”方法迁移现有的sp4 mvc应用程序而不使用@EnableAutoConfiguration ...但是我在创建使用我现有的配置准系统spring-boot-web应用程序。

我的配置:

实现WebApplicationInitializer和@Override启动方法

public class FooWebAppWebApplicationInitializer implements WebApplicationInitializer {

    public static final String SERVLET_NAME = "foo-web-app";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(RootConfig.class);

        // Manage the lifecycle of the root application context
        servletContext.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(SpringMvcConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(SERVLET_NAME, new DispatcherServlet(dispatcherContext));

        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        //Spring security config
        FilterRegistration.Dynamic springSecurityFilterChain = 
                servletContext.addFilter(
                        "securityFilter", new DelegatingFilterProxy("springSecurityFilterChain")
                        );

        springSecurityFilterChain.addMappingForServletNames(null, false, SERVLET_NAME);

        servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);

    }

注意: SpringMvcConfig.class包含@EnableWebMvc注释。

注意:没有使用@Component扫描...在配置类中声明了所有bean 明确

Spring Boot Runner:

@Configuration
public class SpringBootRunner {

    public static void main(String[] args) {

        //SpringApplicationBuilder sab = new SpringApplicationBuilder();
        SpringApplication springApplication 
                    = new SpringApplication(RootConfig.class,
                                            SpringMvcConfig.class);

        springApplication.run(args);
        //SpringApplication.(SpringBootRunner.class, args);
    }

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setPort(9000);
        factory.setSessionTimeout(10, TimeUnit.MINUTES);
        //factory.setErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
        return factory;
    }

}

Maven pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.foo</groupId>
    <artifactId>foo-web-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java-version>1.8</java-version>
    </properties>

    <dependencies>

       //... omitted application specific dependencies 
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
      </dependencies>
    <build>
        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
         </plugins>
</build>

...

我尝试过的事情......

  1. 正如Spring引导文档所述:转换现有的WebApplicationInitializer - &gt; SpringBootServletInitializer并复制/粘贴内容

    • 尝试将SpringBootServletInitializer传递给我的跑步者(结果:服务器启动但我的配置被忽略)

    • 尝试@Override显式传入root / servlet上下文的configure方法

  2. @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        application.sources(RootConfig.class);
        application.child(SpringMvcConfig.class);
        return application.sources(SpringBootServletInitializer.class);
    }
    

    再次导致tomcat服务器启动但我的配置被忽略。

    1. 试图将root和mvc configs直接传递给SpringBootRunner导致...在记录器中加载配置但引发了以下异常
    2. Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
          at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      

      问题:尝试了其他各种方法仍然没有运气。厌倦了猜测。我真的找不到一个我想在任何地方实现的例子。有没有人知道一个示例项目或知道我需要什么转轮/配置来实现我想要的“自下而上”方法迁移到春季启动?

      我只想将现有的sp4 mvc配置迁移到准系统spring-boot-web应用程序,并在每个启动器jar上运行现有的单元/集成测试后启用启动启动器 1 x 1 迁移到。

2 个答案:

答案 0 :(得分:0)

假设您要使用嵌入式容器,请使用以下命令。 (放下你现在拥有的东西)。

@SpringBootApplication
@Import(RootConfig.class, SpringMvcConfig.class)
public class SpringBootRunner extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootRunner.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(SpringBootRunner.class);
    }

}

@Import将导入您自己配置的bean。 (也将此类放在根包中的某个位置(即com.your.app)。虽然有一个@SpringBootApplication注释可以启用自动配置,但这很大程度上会因为你自己配置所有内容而被禁用(Spring Boot是聪明到可以检测出来。)

要更改服务器端口和会话超时,只需添加包含以下内容的application.properties

server.port=9000
server.session.timeout=600 // in seconds!

这应该启动一个嵌入式容器,或者你应该能够将它部署到战争中。现在,您可以逐步从您不需要的配置中删除内容。

Spring Boot已经为您添加了Spring Security过滤器和HiddenHttpMethodFilter(这是您不需要配置的一件事)。将从您提供的配置中使用Spring Security配置。

作为最后评论,Spring Boot启动器不再是一组依赖关系,它对自动配置没有任何作用。因此,您可以自己包含spring-boot-starter-web作为依赖项或包含所有spring-web依赖项。它只不过是便利性,它也负责传递依赖管理。

甚至可以使用启动器(或Spring IO Platform bom)进行依赖关系管理,甚至不使用Spring Boot功能。

答案 1 :(得分:0)

所以......事实证明我尝试过的许多场景都应该起作用,但我在这个问题上遇到了'问题':

How do I add method based security to a Spring Boot project?

基本上,如果您在SAME配置类中将自定义PermissionEvaluator接口bean定义为spring security config ...您将获得这些神秘的异常,并且您的嵌入式tomcat将无法启动。

Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]

解决方法是在自己的 SEPARATE 配置类文件中定义PermissionEvaluator bean。