作者:廖明
随着 Spring Boot 生态社区的日益强大,贝聊服务端团队在开发部分新系统时,也逐步采用了 Spring Boot 框架,并且积累了一定的经验,在此和大家做个分享。
项目采用 Spring Boot ,和直接使用 Spring MVC ,有什么优点了?这里我们分析了下,大概有以下几点:
总结来说,相比于直接使用 Spring MVC 构建项目,Spring Boot 使我们在开发、配置、监控、部署的过程中,都变得更加简单。
在讲Spring Boot 之前,有必要讲下我们贝聊服务端现在有用到的技术栈:
引入Spring Boot ,则必须要支持我们现有的技术栈,并且要能够让新同事能够很快熟悉。依托于Spring Boot 约定优于配置的理念,及官方和社区提供的各种丰富的 Starter pom 配置,在各同事的支持下,各方面的整合,都相对顺利。在接下来的文字里,我会和大家讲解贝聊在使用 Spring Boot 的一些情况。
贝聊服务端使用了 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 来进行分布式作业管理,且一直沿用了较低版本,没有做升级。之前已有的项目,Elastic-Job 的配置和作业都是放在一个 spring-job.xml 文件里面。在整合 Elastic-Job 和 Spring Boot 的时候,发现社区有开源的 spring-boot-starer-elastic-job ,不过采用了最新版的 Elastic-Job-Lite。 在此背景下,我准备了两种方案:
后面和同事讨论下,采用了后面的方案,升级 Elastic-Job 版本为 Elastic-Job-Lite,新项目使用 spring-boot-starter-elastic-job 来配置,并且使用注解来声明作业。至此,又一个 xml 文件被移除。
Discof 是贝聊在早期引进的分布式配置管理工具,使用起来也很简单,虽然原作者已经停止维护,但还是有热心的网友提供了 disconf-spring-boot-starter ,基于此 Starter ,也极大简化了我们在新项目中的配置成本,新入职的同事在配置 Discof 的时候,也不需要再去拷贝旧项目 Diconf 的 xml 配置。
这部分整合是相对容易的,Mybatis 和 Druid 官方,均有提供自动化配置的 Starter pom,拿来开箱即用。
需要特殊处理的是多数据源配置,之前系统用的公司统一的配置类,不过是 xml 配置。为了为复用代码,我们将其转为了 Java Config 的方式,并计划在未来也抽成一个自动化配置的 Starter 包。同样,我们在整合 Shiro 的时候,也是采用了Java Config的形式,并整合了 JWT 作为接口访问令牌。
APM 监控方面,我们公司使用了 Cat,平台组的同事搭建了 Cat,并且提供了对应的整合方式,其中一些配置 Bean 注入的时候,还是使用 xml 的方式,后面笔者将其改为了 Java Config 的方式,总个整合过程如下:
上面的5个步骤中,前面3个步骤是可以合并为一个,2和3两个步骤,可以通过将xml配置变成Java Config 的方式,并生成一个 spring-boot-starter-cat-monitor 包,实现配置类的重用,简化配置步骤。下面也介绍下步骤2和3实现自动化配置的原理:
/** * 功能: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; } }
/** * 功能:dubbo cat 监控,使用Activate注解, 无条件自动激活,不需要在yml 配置中声明该filter 了 */ @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) public class CatBootDubboConfigure extends Filter { //此处省略具体的埋点操作 }
上面说了好些 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
日志效果如下:
刚开始在我们已有的发布系统上部署 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个了,未来还会增加。