转载

SpringBoot在贝聊的应用

作者:廖明

随着 Spring Boot 生态社区的日益强大,贝聊服务端团队在开发部分新系统时,也逐步采用了 Spring Boot 框架,并且积累了一定的经验,在此和大家做个分享。

Spring Boot 的优点

项目采用 Spring Boot ,和直接使用 Spring MVC ,有什么优点了?这里我们分析了下,大概有以下几点:

  • 使用 Java Config 的配置方式替代 xml文件 配置,实现配置类复用。避免每次构建新的 Spring MVC 建项目,都得往旧的项目中拷贝 xml 配置文件。
  • 社区提供的丰富的 Starter pom 依赖包,极大方便了我们整合第三方框架。
  • 提供嵌入式 Servlet 容器,支持 jar 和 war 部署,给运维和开发都带来了极大的便利。
  • 自动管理依赖,勉去版本冲突烦恼。
  • 提供了基本的应用监控的功能。

总结来说,相比于直接使用 Spring MVC 构建项目,Spring Boot 使我们在开发、配置、监控、部署的过程中,都变得更加简单。

Spring Boot 在贝聊的应用情况

在讲Spring Boot 之前,有必要讲下我们贝聊服务端现在有用到的技术栈:

  • 基础框架 Spring MVC。
  • 服务治理方面,使用了 Dubbo。
  • 数据库层面,使用了 Mybatis,Druid,并配置了多数据源。
  • 权限控制用到 Shiro。
  • 分布式配置,使用了 Disconf。
  • 分布式定时任务,使用 Elastic-Job。
  • 全链路监控方面使用了 Cat。
  • 部署方面,我们用自己的发布系统。

引入Spring Boot ,则必须要支持我们现有的技术栈,并且要能够让新同事能够很快熟悉。依托于Spring Boot 约定优于配置的理念,及官方和社区提供的各种丰富的 Starter pom 配置,在各同事的支持下,各方面的整合,都相对顺利。在接下来的文字里,我会和大家讲解贝聊在使用 Spring Boot 的一些情况。

在 Spring Boot 中使用 Dubbo

贝聊服务端使用了 Dubbo 框架来实现服务治理,Dubbo 目前在Apache 孵化器进行孵化,官方也提供了 incubator-dubbo-spring-boot-project ,不过官方的 0.1.0 版本在4月份才发布,在此之前,我们编写了自己的 spring-boot-starter-dubbo,并满足已有需求。

新项目在使用了 spring-boot-starter-dubbo 后,我们在暴露和引入 Dubbo 服务时,均使用了注解的形式,抛弃了原本的 xml 配置方式,开发的时候不用在关注是否在 dubbo.xml 中是否有引入服务,编码时相对轻松了不少。

和 Elastic-Job-Lite 整合

贝聊在很早的时候,就使用了 Elastic-Job 来进行分布式作业管理,且一直沿用了较低版本,没有做升级。之前已有的项目,Elastic-Job 的配置和作业都是放在一个 spring-job.xml 文件里面。在整合 Elastic-Job 和 Spring Boot 的时候,发现社区有开源的 spring-boot-starer-elastic-job ,不过采用了最新版的 Elastic-Job-Lite。 在此背景下,我准备了两种方案:

  • 采用 @ImportResource({"classpath:spring-job.xml"}) 方式来兼容旧版本的 Elastic-Job 的任务,自己在写 demo 时运行正常;
  • 升级 Elastic-Job 版本为 Elastic-Job-Lite,并安装最新版的 Elastic-Console ,参考社区的 Starter ,编写使用注解方式配置定时任务,去 xml;

后面和同事讨论下,采用了后面的方案,升级 Elastic-Job 版本为 Elastic-Job-Lite,新项目使用 spring-boot-starter-elastic-job 来配置,并且使用注解来声明作业。至此,又一个 xml 文件被移除。

和 Disconf 整合

Discof 是贝聊在早期引进的分布式配置管理工具,使用起来也很简单,虽然原作者已经停止维护,但还是有热心的网友提供了 disconf-spring-boot-starter ,基于此 Starter ,也极大简化了我们在新项目中的配置成本,新入职的同事在配置 Discof 的时候,也不需要再去拷贝旧项目 Diconf 的 xml 配置。

和 Mybatis、Druid 以及多数据源整合

这部分整合是相对容易的,Mybatis 和 Druid 官方,均有提供自动化配置的 Starter pom,拿来开箱即用。

需要特殊处理的是多数据源配置,之前系统用的公司统一的配置类,不过是 xml 配置。为了为复用代码,我们将其转为了 Java Config 的方式,并计划在未来也抽成一个自动化配置的 Starter 包。同样,我们在整合 Shiro 的时候,也是采用了Java Config的形式,并整合了 JWT 作为接口访问令牌。

和 Cat 监控整合

APM 监控方面,我们公司使用了 Cat,平台组的同事搭建了 Cat,并且提供了对应的整合方式,其中一些配置 Bean 注入的时候,还是使用 xml 的方式,后面笔者将其改为了 Java Config 的方式,总个整合过程如下:

  • 1、引入Cat 相关 jar 包;
  • 2、如果是 web 项目,要注入 CatServletFilter ,实现 MVC层Cat 配置;
  • 3、如果是项目中用到了 Dubbo ,添加 CatDubboFilter
  • 4、在 META-INF 中添加 app.properties ,声明项目名字;
  • 5、在 logback-spring.xml 中添加 CatLogbackAppender 配置;

上面的5个步骤中,前面3个步骤是可以合并为一个,2和3两个步骤,可以通过将xml配置变成Java Config 的方式,并生成一个 spring-boot-starter-cat-monitor 包,实现配置类的重用,简化配置步骤。下面也介绍下步骤2和3实现自动化配置的原理:

  • 注入CatServletFilter,主要是利用 @ConditionalOnWebApplication 注解,如果当前环境是web环境,则该配置类会生效,核心代码如下:
/**
 * 功能:web 环境下,集成cat监控功能
 */
@Configuration
@ConditionalOnWebApplication
public class CatWebFilterConfigure {

    @Bean
    public FilterRegistrationBean catFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CatServletFilter());
        registration.addUrlPatterns("/*");
        registration.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.FORWARD);
        registration.setName("cat-filter");
        return registration;
    }
}
  • 注入CatDubboFilter,主要是利用Dubbo的 @Activate 来无条件激活配置。因为我们所有的项目,都整合了Dubbo,所以不需要根据环境来注入配置类。
/**
 * 功能:dubbo cat 监控,使用Activate注解, 无条件自动激活,不需要在yml 配置中声明该filter 了
 */
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
public class CatBootDubboConfigure extends Filter {
    //此处省略具体的埋点操作
}

使用 spring-boot-start-web-log 统一拦截请求和响应日志

上面说了好些 Starter ,都是用了社区已有的轮子,当然,我们团部内部,也有封装一些简单的 Starter ,以实现代码复用,简化配置。

我们在日常接口开发的调试阶段,经常需要查看接口请求和响应日志。使用 Spring 来拦截接口请求和响应日志,有多种实现方式,可以自己定义 Filter,Intercepter,或者使用 Aspectj,如果每一个 Web 项目,都来写一套实现,或者从别的项目中拷贝一份,这肯定不是一个好的方式。基于此情况,践行 Spring Boot 约定优于配置的原则,我们自己内部封装了 spring-boot-start-web-log ,并提供了一些常见的配置项。新的 Web 项目需要时,只需要引入依赖,并在 yml 配置文件中加入如下配置就好:

web.log:
    ## 拦截路径
    mapping-path: "/*"
    ## 排除路径
    exclude-mapping-path: "/files/*;/favicon.ico;/login;/captcha/*
    ## 打印header,多个按照';'分隔
    print-header: "Authorization"
    ## 是否允许打印日志,默认true,建议生成关闭
    enable: true

日志效果如下:

SpringBoot在贝聊的应用

在已有发布系统上部署 Spring Boot 应用

刚开始在我们已有的发布系统上部署 Spring Boot 应用时,遇到了一些问题。

在部署应用方面,我们尝试了 war 包部署和 jar 部署两种方式。其中采用 war 包部署时,发现会和现有的 Resin 有冲突,需要移除 Resion 的部分 jar ,比较麻烦,所以我们采用 jar 包部署的方式。

使用 jar 包部署,我们也遇到了一些问题。我们已有的 Dubbo 应用部署,就是采用了 jar 包部署。去除一些 JVM 参数是可配置的,最终都是使用到 java -cp jar包路径 类名 的命令来运行应用。注意,这种方式,是需要指定jar路径和类名的,和 java -jar spring-boot-app.jar 是不一样的,因此,为了避免脚本改动,我们得适配现有的发布脚本。

Dubbo 打成可独立运行的 jar 包,使用了 maven-shade-plugin 插件,指定的类名是 com.alibaba.dubbo.container.Main 。而在打包 Spring Boot 应用时,我们采用了 spring-boot-maven-plugin 插件 。在选择 java -cp 命令所需要参数类名时,我们刚开始使用了Spring Boot默认的 Application 启动类,毕竟我们开发的时候,也是直接运行该类的 main 方法来启动应用。然而实际运行的时候,发现应用根本起不来,提示找不到或无法加载主类。后面经过一番资料查找与学习,才解决了该问题。

解决问题的关键,在于要了解 jar 运行的原理,也就是 MANIFEST.MF 文件。 解压Spring Boot 打包后的jar文件,其中 MANIFEST.MF 文件如下:

Manifest-Version: 1.0
Implementation-Title: demo
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: Ming
Implementation-Vendor-Id: com.beiliao.app
Spring-Boot-Version: 1.5.4.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.beiliao.app.DemoApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.3.1
Build-Jdk: 1.8.0_73
Implementation-URL: http://projects.spring.io/spring-boot/demo/

注意到这里面 Main-Class: org.springframework.boot.loader.JarLauncher 才是主方法,使用 java -jar spring-boot-app.jar 可以运行Spring Boot 应用,是因为 spring-boot-maven-plugin 插件在打包的时候已经生成该文件 , java -jar 命令会读取到该文件 。因此,使用 java -cp 命令启动 Spring Boot 应用时,完整的命令应该是:

windows:
java -cp .;c://Project//boot-demo//target//demo-0.0.1-SNAPSHOT.jar  org.springframework.boot.loader.JarLauncher
linux:
java -cp .:/data/project/demo/*  org.springframework.boot.loader.JarLauncher

总结

以上就是Spring Boot 在贝聊的一些应用情况。目前,贝聊已经有几个新项目使用到 Spring Boot,并在组内反响不错,用过的开发同事多说比之前直接用 Spring MVC 要方便不少。公司 Gitlab 仓库的 Starter 依赖包也有6个了,未来还会增加。

原文  https://juejin.im/post/5b0e40be6fb9a00a1a59806d
正文到此结束
Loading...