云上持续交付实践系列1 --- java 篇

简介: 本文会演示如何在CRP上编译并部署一个Java Web应用。 我的应用 技术栈 我的应用是一个简单的在线购书的网站。因为是示例,所以代码就只有简单的一个登陆界面和登陆以后的书目列表界面。代码库在https://code.aliyun.com/blade_1986/bookstore。 使用的技

本文会演示如何在CRP上编译并部署一个Java Web应用。

我的应用

技术栈

我的应用是一个简单的在线购书的网站。因为是示例,所以代码就只有简单的一个登陆界面和登陆以后的书目列表界面。代码库在https://code.aliyun.com/blade_1986/bookstore。 使用的技术栈如下:

  1. Gradle作为构建工具
  2. Spring作为IOC容器及MVC框架
  3. JUnit作为测试框架
  4. Spring Test作为集成测试框架
  5. Selenium作为功能测试工具

有兴趣的同学可以先把这个代码下载下来按照README.md现在本地跑起来。

部署环境

我有两台ECS的机器,都有公网IP,并且开放了22端口。我选择其中的一台做我的预发环境,另一台做我的正式环境,它们是:

  • 预发环境:120.xx.xx.103
  • 正式环境:120.xx.xx.137

在CRP上编译该项目的预备工作

使用gradle wrapper及CRP下载源

该项目使用的是gradle的官方推荐用法:gradle wrapper。使用这种方式,第一次运行./gradlew命令时,会下载相应版本的gradle发行版本下来,然后执行接下来的命令。直接从gradle官方下载gradle发行版本会比较慢,所以我按照这篇文章的引导修改了下载源,运行起./gradlew来速度杠杠的。

使用maven.aliyun.com

直接使用maven的库速度会有些慢,所以可以将依赖库的地址配置到我们的maven.aliyun.com来加速编译。该库代理了maven的官方库。但如果某个你访问的库在maven.aliyun.com中不存在的话,则第一次编译可能会超时失败,但第二次就可以成功了。修改方式是在build.gradle中添加如下配置:

repositories {
    maven{ url 'http://maven.aliyun.com/nexus/content/groups/public'}
}

开始进行配置

在CRP中创建了项目之后,可以选择新建工作流,默认会提示从模板创建,我选择了“JAVA工程标准模板”,输入项目名称“bookstore”,然后点击确认,就会看到这样的页面:
_2016_04_09_10_46_38

关联代码库并配置触发器

看到上面大大的“点我配置触发器”,于是就点了一下,然后尝试去选择代码仓库和侦听分支,发现什么都没有。那是因为没有将该代码库与该项目进行关联。需要点击侧边栏的“代码管理”,然后在关联代码库的输入框内输入“bookstore”,然后CRP就可以自动提输出该代码库的全名,然后点击添加就可以把该代码库关联到这个项目了。然后再回到工作流配置界面,点击触发器按钮,去配置代码库及侦听分支。如果你想尝试这个步骤,需要先把上述的代码库fork一份出来到你的code.aliyun.com的账户下,因为非代码库成员的CRP账户无法关联该代码库。

完成代码库配置后我们来看看这个模板都包含了什么。

持续集成的配置

第一个阶段叫做代码检出-单元测试,其中自动加入了两个任务,我们只需要关注"编译/测试"这个任务即可。这个任务的目标是对代码进行验证,并打一个war包出来,以供后续的部署之用。该任务的默认配置如下图所示:
_2016_04_09_10_55_08
可以看到默认命令使用的是maven。而我使用的是gradle,所以需要做相应变化。我会使用下面的命令来运行单元测试和集成测试:

./gradlew test integrationTest
./gradlew war

运行完之后生成的war包会在build/libs/bookstore.war。所以修改完的配置如下所示:
_2016_04_09_11_02_16
到此为止我们就配置好了测试,点击右上角的生效后,再点击右上角的触发,工作流就开始运行了。点击控制台输出可以看到任务运行的日志。
_2016_04_09_11_10_15

发布的配置

预发环境

接下来我想要把代码部署到预发环境了,但是模板只给了我一个“正式部署”。没关系,这只是个名字而已,点击这个活动把名字改了就好:
_2016_04_09_11_13_14
上面是默认配置,下面解释一下每个配置的含义:

  • 目标机器就应该是我预发机器的IP:120.xx.xx.103
  • 部署路径:CRP会把我生成的bookstore.war这个文件再压缩成为一个package.tgz文件。当部署任务运行时,CRP会把这个package.tgz拷贝到我指定的“部署路径”中。我直接将其指定到了/root下。
  • 部署命令:这个就是当拷贝完成之后用来部署的脚本。那我的脚本要做什么呢?很简单,停止tomcat,把war包拷贝到tomcat的webapps目录下,然后再启动tomcat,that's it!

所以最后我的配置是这样的:
39fd69ab7c10496a43067e32281d9c101f548748
CRP会默认在登录用户的home目录下执行这些命令。由于我用root账户登录,而该用户的home目录就是/root,所以可以直接开始执行解压的命令。如果你拷贝的位置不是登录用户的home目录,则需要先cd过去。

哦对了,CRP如何才能访问你的机器?需要点击配置框右下角的“机器授权”来完成这件事情。

正式环境

配置好了预发环境,接下来要配置正式环境了。聪明的你可能已经想到了,配置方面除了“目标机器”的IP不同之外,其它的所有配置都跟预发环境是一模一样的(不要忘记再次配置机器授权!)。

一些细节的配置

我希望自动化测试和打包这件事情在每次提交代码之后自动发生,但是我希望经过手工批准才能进行两个配置任务。所以三个活动中,第一个活动是自动触发的,后面两个都需要手动批准。这个配置是通过活动信息的“自动触发”和“自动完成”两个选项生效的:
_2016_04_09_11_29_17
单元测试活动两个都勾选了;两个部署活动只勾选了自动完成。

当然我还希望单元测试出错时候能够通过邮件提示我,所以我还选中上图中的“异常通知”来。而部署的操作肯定是在页面上进行的,所以如果出错立马就能看到,所以这个就不需要配置邮件通知了。

运行完第一个活动后:
_2016_04_09_11_27_18
点击三角符号才会触发预发环境的部署。运行结束后你会看到:
_2016_04_09_11_28_31
再次点击那个按钮之后就可以触发生产环境的配置。运行结束后你会看到:
_2016_04_09_11_32_15

配置精简

作为一个视重复为万恶之源的程序员,我发现了“预发部署”的配置和“产品部署”的配置在“部署命令”这个输入框中的内容是一模一样的!所以我需要像个办法来精简一下。做法很简单,那就是把这些命令放到deploy.sh这个部署脚本中,然后把bookstore.wardeploy.sh这两个文件达成一个压缩包,名为bookstore.zip。然后CRP会把bookstore.zip再打成package.tgz。所以我们的CRP中的配置脚本就可以简化为:

  1. 解压package.tgz
  2. 解压bookstore.zip
  3. 运行deploy.sh来进行部署

为了做到这一点,首先第一个活动的配置需要改为:
_2016_04_10_3_58_09
然后两个部署的配置均可改为:

tar -xvf package.tgz
rm -rf bookstore
unzip bookstore.zip -d bookstore
cd bookstore
sh deploy.sh

当然现在看起来还是有些不可避免的冗余,CRP后续会再对此再作一些优化。

更多

在上述的例子中,你已经学会了如何把对你的应用做持续集成,并把它部署到预发和产品环境。但这并不是全部。你可能还会关心下面的几个话题。

多机部署

这个例子在一个环境中只部署了一台机器,显然这无法满足无感知发布的需求。后续我会写一篇结合阿里云SLB进行无感知发布的文章。

数据库

简单起见,本示例没有连接数据库。如果需要在测试中使用数据库的话,需要自行安装数据库,具体的安装方法请参看这里

功能测试

如你所见,示例项目中其实有使用selenium编写的功能测试,但并没有配置到CRP的工作流中。我会在后续的文章中详细描述这部分内容。

目录
相关文章
|
4月前
|
SQL 缓存 安全
深度理解 Java 内存模型:从并发基石到实践应用
本文深入解析 Java 内存模型(JMM),涵盖其在并发编程中的核心作用与实践应用。内容包括 JMM 解决的可见性、原子性和有序性问题,线程与内存的交互机制,volatile、synchronized 和 happens-before 等关键机制的使用,以及在单例模式、线程通信等场景中的实战案例。同时,还介绍了常见并发 Bug 的排查与解决方案,帮助开发者写出高效、线程安全的 Java 程序。
237 0
|
4月前
|
存储 搜索推荐 算法
Java 大视界 -- Java 大数据在智慧文旅旅游线路规划与游客流量均衡调控中的应用实践(196)
本实践案例深入探讨了Java大数据技术在智慧文旅中的创新应用,聚焦旅游线路规划与游客流量调控难题。通过整合多源数据、构建用户画像、开发个性化推荐算法及流量预测模型,实现了旅游线路的精准推荐与流量的科学调控。在某旅游城市的落地实践中,游客满意度显著提升,景区流量分布更加均衡,充分展现了Java大数据技术在推动文旅产业智能化升级中的核心价值与广阔前景。
|
4月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
150 0
|
4月前
|
并行计算 Java API
Java List 集合结合 Java 17 新特性与现代开发实践的深度解析及实战指南 Java List 集合
本文深入解析Java 17中List集合的现代用法,结合函数式编程、Stream API、密封类、模式匹配等新特性,通过实操案例讲解数据处理、并行计算、响应式编程等场景下的高级应用,帮助开发者提升集合操作效率与代码质量。
224 1
|
4月前
|
存储 Java 大数据
Java 大视界 —— 基于 Java 的大数据隐私保护在金融客户信息管理中的实践与挑战(178)
本文探讨了基于 Java 的大数据隐私保护技术在金融客户信息管理中的应用与挑战。随着金融行业数字化转型加速,客户信息的安全性愈发重要。文章详细分析了数据加密、脱敏、访问控制、区块链及联邦学习等关键技术,并结合实际案例展示了其在金融机构中的应用效果,为金融科技从业者提供了宝贵的实践经验与技术参考。
|
4月前
|
安全 Java API
Java 17 及以上版本核心特性在现代开发实践中的深度应用与高效实践方法 Java 开发实践
本项目以“学生成绩管理系统”为例,深入实践Java 17+核心特性与现代开发技术。采用Spring Boot 3.1、WebFlux、R2DBC等构建响应式应用,结合Record类、模式匹配、Stream优化等新特性提升代码质量。涵盖容器化部署(Docker)、自动化测试、性能优化及安全加固,全面展示Java最新技术在实际项目中的应用,助力开发者掌握现代化Java开发方法。
222 1
|
5月前
|
数据采集 机器学习/深度学习 Java
Java 大视界 —— Java 大数据在智慧交通停车场智能管理与车位预测中的应用实践(174)
本文围绕 Java 大数据在智慧交通停车场智能管理与车位预测中的应用展开,深入剖析行业痛点,系统阐述大数据技术的应用架构,结合大型体育中心停车场案例,展示系统实施过程与显著成效,提供极具实操价值的技术方案。
|
5月前
|
前端开发 数据可视化 Java
开发 JavaFX 与 Java Swing 桌面应用的实用技巧与实践方案
本文介绍了Java桌面应用开发的技术选型与JavaFX实战方案。首先对比了JavaFX和Swing的特点,推荐JavaFX更适合现代UI需求。重点讲解了JavaFX 19+的技术升级,包括模块化开发(module-info.java配置)和响应式UI设计(CSS样式管理)。在数据访问层展示了JDBC 4.3的集成和异步加载实现。高级UI组件部分演示了自定义表格和图表可视化的开发方法。最后介绍了MVVM架构的实现,包括视图模型的数据绑定和FXML控制器的集成,为开发者提供了完整的JavaFX桌面应用开发解决方案。
375 0
|
5月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
230 1
|
5月前
|
安全 Java API
Java 抽象类与接口在 Java17 + 开发中的现代应用实践解析
《Java抽象类与接口核心技术解析》 摘要:本文全面剖析Java抽象类与接口的核心概念与技术差异。抽象类通过模板设计实现代码复用,支持具体方法与状态管理;接口则定义行为规范,实现多态支持。文章详细对比了两者在实例化、方法实现、继承机制等方面的区别,并提供了模板方法模式(抽象类)和策略模式(接口)的典型应用示例。特别指出Java8+新特性为接口带来的灵活性提升,包括默认方法和静态方法。最后给出最佳实践建议:优先使用接口定义行为规范,通过抽象类实现代码复用,合理组合两者构建灵活架构。
176 2