全部产品
云市场

SOFABoot 应用部署到 J2EE 容器

更新时间:2019-09-05 19:38:13

简单来说,基于 Spring Boot 的 SOFABoot 应用部署到 J2EE 容器中,就是使用的原有应用容器不变,仍旧是您之前需要依赖的 Tomcat 或者 Jetty,同时应用也是打包成 war 包进行部署;而您的框架需要升级为用 Spring Boot 进行开发,同时基于的标准是 Servlet 3.0(显著的变化是无 web.xml 的配置),您需要将您的原有配置升级为用 Servlet 3.0 配置即可。

基于 Spring Boot 的 SOFABoot 应用也可以部署在传统的 J2EE 容器中,由于默认 Spring Boot 的初始化方式是以 Servlet 3.0 标准的方式完成 Servlet 的初始化工作的,也就是不需要任何额外的 web.xml 配置。您可以按照如下的方式升级您的开发框架到 SOFABoot(也就可以使用所有 Spring Boot 相关的特性):

参考文档:基于 Servlet 3.0 规范打包成 war 包

参考文档:Deploying a WAR in an Old (Servlet 2.5) Container

修改 Maven 相关依赖并增加相应代码

  • 增加 SOFALite 依赖

    1. <dependency>
    2. <groupId>com.alipay.boot</groupId>
    3. <artifactId>slite2-dependencies</artifactId>
    4. <version>1.0.0</version>
    5. <type>pom</type>
    6. <scope>import</scope>
    7. </dependency>
  • 引入您想使用的中间件,如:

    1. <dependency>
    2. <groupId>com.alipay.boot</groupId>
    3. <artifactId>sofarpc-spring-boot-starter</artifactId>
    4. </dependency>
  • 增加 web 的模块依赖,如:

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-web</artifactId>
    4. <scope>provided</scope>
    5. </dependency>
  • 增加一个 Maven 的打包插件,即使用 spring-boot-maven-plugin

    1. <plugin>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-maven-plugin</artifactId>
    4. <version>1.4.2.RELEASE</version>
    5. <configuration>
    6. <mainClass>com.antcloud.tutorial.rpc.SpringBootSOFALite2ClientApplication</mainClass>
    7. <!-- 可选保证将您的 war 打包到工程的根目录下 -->
    8. <outputDirectory>../../target</outputDirectory>
    9. </configuration>
    10. <executions>
    11. <execution>
    12. <goals>
    13. <goal>repackage</goal>
    14. </goals>
    15. </execution>
    16. </executions>
    17. </plugin>
  • 假设默认您是基于 Servlet 3.0,那么您可以利用 ServletContextInitializer 特性,Spring 已经为您提供了一个实现,那就是 org.springframework.web.SpringServletContainerInitializer,您在传统的 J2EE 上开发基于 Spring Boot 的应用,依赖这个特性做启动和初始化工作,需要您在一个主函数中增加如下的代码:

    1. @org.springframework.boot.autoconfigure.SpringBootApplication
    2. @ImportResource(value = "/${path}/${to}/${spring}/${applicationContext}")
    3. public class SpringBootSOFALite2ClientApplication extends SpringBootServletInitializer {
    4. // 在Java类中创建 logger 实例
    5. private static final Logger logger = LoggerFactory.getLogger(SpringBootSOFALite2ClientApplication.class);
    6. private static Class<SpringBootSOFALite2ClientApplication> applicationClass = SpringBootSOFALite2ClientApplication.class;
    7. @Override
    8. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    9. return application.sources(applicationClass);
    10. }
    11. public static void main(String[] args) {
    12. SpringApplication springApplication = new SpringApplication(SpringBootSOFALite2ClientApplication.class);
    13. ApplicationContext applicationContext = springApplication.run(args);
    14. }

    具体文档可以参考 Traditional Deployment。注意:在传统的 web.xml 配置中您会配置类似如下的参数来制定 Spring 的初始化配置文件位置,如:

    1. <context-param>
    2. <param-name>contextConfigLocation</param-name>
    3. <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    4. </context-param>

    这段代码其实是指定 ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml] 用于初始化 Spring 上下文,在升级的框架中您可以直接利用 @ImportResource 来启动加载配置文件,而完全的基于 Servlet 3.0(无 web.xml)。

  • 运行

    首先执行 mvn clean install -DskipTests 打包,然后可以在配置了 Jetty 插件后执行 mvn jetty:run 或者 mvn spring-boot:run

    如果部署的容器使用的版本还是基于Sevlet 2.5 基于 web.xml 的方式,运行一个 Spring Boot 的应用可以 参考这里

FAQ

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml

Spring Boot 应用在 J2EE 容器初始化运行的时候,会在 org.springframework.boot.web.support.SpringBootServletInitializer#onStartup 中初始化 org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext

  1. WebApplicationContext rootAppContext = createRootApplicationContext(
  2. servletContext);
  3. if (rootAppContext != null) {
  4. servletContext.addListener(new ContextLoaderListener(rootAppContext) {
  5. @Override
  6. public void contextInitialized(ServletContextEvent event) {
  7. // no-op because the application context is already initialized
  8. }
  9. });
  10. }

这时,基于 Spring Boot 的应用中就已经添加了 ContextLoaderListener 的实现。

但如果您的 web.xml 中也配置了类似如下的内容:

  1. <listener>
  2. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3. </listener>

由于在 org.springframework.boot.web.support.SpringBootServletInitializer 中已经初始化完成了,所以就会产生错误。

所以在您的 web.xml 中应该删除相关配置,以避免冲突。web.xml 删除后,可以使用 Servlet 3.0 注解的方式完善配置或利用上文介绍的 @ImportResource