当前位置: 首页 > 知识库问答 >
问题:

如何在没有@EnableAutoConfig的情况下使用“自下而上”的方法迁移现有的Spring mvc应用程序

陶弘业
2023-03-14

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

到目前为止,我在文档中阅读到的所有解决方案都采用了“自顶向下”的方法,其中他们建议导入您需要的所有starter JAR,以及随时间推移不需要的“启用自动配置”和“关闭”配置。我认为,如果您从头开始,这种“自上而下”的方法非常有效,但如果您正在迁移现有的应用程序,这种方法就不行了。

问题:话虽如此,我正在尝试通过“自下而上”的方法迁移我现有的sp4 mvc应用程序,而无需@EnableAutoConfiguration......但我在创建一个准系统sping-boot-web应用程序时遇到了麻烦与我现有的配置。

我的配置:

它实现了WebApplicationInitializer和@重写启动方法

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>

...

我试过的事情。。。

>

>

  • 尝试将SpringBootServletLaunalizer传递给我的运行程序(结果:服务器启动,但我的配置被忽略)

    尝试重写显式传递到根/servlet上下文中的configure方法

    .

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

    这再次导致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]
    

    问题:尝试了各种其他方法,但仍然没有成功。厌倦了猜测。我真的找不到一个例子来说明我正在努力实现什么。有人知道一个示例项目,或者知道我需要什么运行程序/配置来实现我想要的“自底向上”方法,以便迁移到spring boot吗?

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

  • 共有2个答案

    缪宪
    2023-03-14

    因此...事实证明,我尝试的许多场景都应该奏效,但我被这个问题“抓住了”:

    如何向Spring Boot项目添加基于方法的安全性?

    基本上,如果您在SAME配置类中定义了一个自定义PermissionEvalator接口bean作为Spring Security配置......您将获得这些神秘的异常,并且您的嵌入式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]
    

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

    端木骞尧
    2023-03-14

    假设您想使用嵌入式容器,请使用以下内容。(放下您现在拥有的内容)。

    @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足够聪明,可以检测到这一点)。

    要更改服务器端口和会话超时,只需添加一个应用程序。包含以下内容的属性

    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平台bom)进行依赖关系管理,而无需使用Spring Boot功能

     类似资料:
    • 我有一个问题要解决,我应该在哪里从使用Java8 streams的员工列表中找到性别为男性的第n个员工,如果没有找到,则返回可选的空。 下面是接受Employee对象列表和整数n的方法,其中n表示必须返回的第n个男性雇员(如果存在的话)。

    • 我看到的所有解决方案都需要使用。但是,我想在Eclipse之外的单个文件上使用CDT解析器。那有什么办法吗?

    • 问题内容: 我从Vaadin开始,我想知道在不使用maven的情况下在NetBeans中使用此框架是否可行。原因是使用maven的项目需要很长时间才能下载依赖项,并且由于超时连接问题而无法运行。 我已经下载了“多合一”文件,并尝试按照这些README.txt文件的说明进行操作: 将除vaadin-client和vaadin-client-compiler以外的所有vaadin- *文件复制到项目中

    • 我想在Java Spring boot中获取我的应用程序的当前url。但问题是,我想从类而不是从中获得它。我试图从获取这个,但我无法将其包导入我的类。 请帮我得到我的网站的网址,不应该硬编码。或者如果有一种方法可以使用到我的util类。

    • 我有一个带有私有方法的类,该方法调用一些外部类并执行它,如果不使用powermock,我如何防止这种情况发生?(该项目使用Junit5,目前还不支持powermock)。 我考虑过将这些函数移到外面,但我觉得有时方法确实属于特定的类,因为它们是它的一部分,将它们移出对我来说没有意义,下面只是一个例子来说明。 我已经知道大多数人会说不要测试私有方法,但a.我不完全同意,b.我不想在这里测试这个方法,

    • 我正在玩grpc 有人成功使用进行生产吗?我们需要包括特使在内的所有依赖项吗?