# 87.3 将现有的应用转换为Spring Boot

对于一个非web项目，转换为Spring Boot应用很容易（抛弃创建`ApplicationContext`的代码，取而代之的是调用`SpringApplication`或`SpringApplicationBuilder`）。Spring MVC web应用通常先创建一个可部署的war应用，然后将它迁移为一个可执行的war或jar。建议阅读[Getting Started Guide on Converting a jar to a war.](https://spring.io/guides/gs/convert-jar-to-war/)。

通过继承`SpringBootServletInitializer`创建一个可执行war（比如，在一个名为`Application`的类中），然后添加Spring Boot的`@SpringBootApplication`注解，示例：

```java
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        // Customize the application or call application.sources(...) to add sources
        // Since our example is itself a @Configuration class (via @SpringBootApplication)
        // we actually don't need to override this method.
        return application;
    }

}
```

记住不管你往`sources`放什么东西，它仅是一个Spring `ApplicationContext`，正常情况下，任何生效的在这里也会起作用。有一些beans你可以先移除，然后让Spring Boot提供它的默认实现，不过有可能需要先完成一些事情。

静态资源可以移到classpath根目录下的`/public`（或`/static`，`/resources`，`/META-INF/resources`）。同样的方式也适合于`messages.properties`（Spring Boot在classpath根目录下自动发现这些配置）。

美妙的（Vanilla usage of）Spring `DispatcherServlet`和Spring Security不需要改变。如果你的应用有其他特性，比如使用其他servlets或filters，那你可能需要添加一些配置到你的`Application`上下文中，按以下操作替换`web.xml`的那些元素：

* 在容器中安装一个`Servlet`或`ServletRegistrationBean`类型的`@Bean`，就好像`web.xml`中的`<servlet/>`和`<servlet-mapping/>`。
* 同样的添加一个`Filter`或`FilterRegistrationBean`类型的`@Bean`（类似于`<filter/>`和`<filter-mapping/>`）。
* 在XML文件中的`ApplicationContext`可以通过`@ImportResource`添加到你的`Application`中。简单的情况下，大量使用注解配置可以在几行内定义`@Bean`定义。

一旦war可以使用，我们就通过添加一个main方法到`Application`来让它可以执行，比如：

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

**注** 如果你想要把你的应用作为war或者可执行的应用来启动，你需要在一个方法里面共享构建器的配置。那个方法要对`SpringBootServletInitializer`回调和`main`方法都可用，就像这样:

```java
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return configureApplication(builder);
    }

    public static void main(String[] args) {
        configureApplication(new SpringApplicationBuilder()).run(args);
    }

    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
        return builder.sources(Application.class).bannerMode(Banner.Mode.OFF);
    }

}
```

应用可以划分为多个类别：

* 没有web.xml的Servlet 3.0+应用
* 有web.xml的应用
* 有上下文层次的应用
* 没有上下文层次的应用

所有这些都可以进行适当的转化，但每个可能需要稍微不同的技术。

Servlet 3.0+的应用转化的相当简单，如果它们已经使用Spring Servlet 3.0+初始化器辅助类。通常所有来自一个存在的`WebApplicationInitializer`的代码可以移到一个`SpringBootServletInitializer`中。如果一个存在的应用有多个`ApplicationContext`（比如，如果它使用`AbstractDispatcherServletInitializer`），那你可以将所有上下文源放进一个单一的`SpringApplication`。你遇到的主要难题可能是如果那样不能工作，那你就要维护上下文层次。参考示例[entry on building a hierarchy](https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#howto-build-an-application-context-hierarchy)。一个存在的包含web相关特性的父上下文通常需要分解，这样所有的`ServletContextAware`组件都处于子上下文中。

对于还不是Spring应用的应用来说，上面的指南有助于你把应用转换为一个Spring Boot应用。然而，你可能会遇到一些问题。在这种情况下，我们建议[使用spring-boot标签在Stack Overflow上提问](https://stackoverflow.com/questions/tagged/spring-boot)。
