基于Ant的持续集成环境

需求

​ 项目组有一套企业级JavaWeb应用,以前在发布新版本时,都是通过ant将核心源码混淆后打成jar,再通过开发工具导出成war包,然后将加密混淆后的jar添加到war包中,部署到tomcat中。整个流程虽然不够复杂,但整个流程下来至少30分钟。最初的想法就是想让这一切工作全部自动化,节省项目新版本发布时间。

软件选择

​ 考察了一些现有持续集成软件,觉得Jenkins 和 Ant都能满足需求。

​ Jenkins 功能很强大:UI界面、邮件通知、测试报告、分布式构建、多种插件支持。想学习建议参考这篇就够了《Jenkins入门系列之——03PDF文档下载

​ 考虑到现有环境一个Ant足以,而且对Ant相对有些了解,所以决定使用Ant搞定持续集成环境。

基于Ant的持续集成环境

环境准备

  • JDK 安装:提供java编译与运行环境

  • Ant 安装并配置环境变量

1
2
3
cd /usr/
wget http://mirrors.hust.edu.cn/apache//ant/binaries/apache-ant-1.9.13-bin.tar.gz
tar -zxvf apache-ant-1.9.13-bin.tar.gz
  • Ant 配置环境变量vi /etc/profile 编辑成功后执行source /etc/profile
1
2
export ANT_HOME=/usr/apache-ant-1.9.13
export PATH=$PATH:$ANT_HOME/bin
  • 目录准备
1
2
3
4
5
6
7
8
9
[tomcat@localhost packageEnv]$ pwd
/home/tomcat/packageEnv
[tomcat@localhost packageEnv]$
[tomcat@localhost packageEnv]$ ll
-rw-rw-r-- 1 tomcat tomcat 14606 12月 24 17:06 build.xml //核心build文件
drwxrwxr-x 5 tomcat tomcat 59 12月 25 19:49 checkout //svn源码检出目录
drwxrwxr-x 2 tomcat tomcat 131 12月 25 19:52 encryption //加密程序存放目录
drwxr-xr-x 9 tomcat tomcat 4096 12月 19 10:10 smartam //tomcat软件目录,已经更名smartam
[tomcat@localhost packageEnv]$
  • svnant准备

实现ant可以从svn服务器上检出代码要使用svnant相关的jar文件。

下载地址:http://subclipse.tigris.org/files/documents/906/49042/svnant-1.3.1.zip

将下载好的svnant解压将 ib目录下的所有jar复制到ant主目录中的lib目录下。

build 流程

  1. properties配置文件准备
  2. 打印环境及 properties信息
  3. 停止tomcat
  4. 定义ant.svn.classpath,使用svn任务时可以使用
  5. 设置svn相关属性
  6. 清理旧文件
  7. 创建初始化目录结构
  8. 从svn 检出源码
  9. 初始化classpath
  10. 编译java源码
  11. 将class文件打成 jar包
  12. 混淆源代码
  13. 将混淆后的jar包加密
  14. 打成war包
  15. 将war包部署tomcat
  16. 启动tomcat

整个流程下来我们只需要登录目标服务器,切换到/home/tomcat/packageEnv 目录,执行ant命令即可。

核心build.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
<?xml version="1.0" encoding="UTF-8"?>
<project name="smartam" default="start_tomcat" basedir="./">
<property environment="env"/>
<property name="webapp.name" value="smartam"/>
<property name="ant.name" value="/usr/apache-ant-1.9.13"/>
<property name="svn.url" value="svn://127.0.0.1/smartam"/>
<property name="svn.username" value="rocklei123"/>
<property name="svn.password" value="xxxxxx"/>
<property name="svn.checkout.dir" value="${basedir}/checkout"/>
<property name="svn.checkout.project" value="${svn.checkout.dir}/${webapp.name}"/>
<property name="catalina.home" value="/home/tomcat/packageEnv/smartam"/>
<property name="dist.dir" value="${svn.checkout.dir}/dist"/>
<property name="build.dir" value="${svn.checkout.dir}/build"/>
<property name="build.class" value="${build.dir}/classes"/>
<property name="build.config" value="${build.dir}/META-INF"/>
<property name="webRoot.dir" value="${svn.checkout.project}/WebRoot"/>
<property name="src.dir" value="${svn.checkout.project}/src"/>
<property name="metainf.dir" value="${svn.checkout.project}/src/META-INF"/>
<property name="lib.dir" value="${webRoot.dir}/WEB-INF/lib"/>
<property name="app.jar" value="${webapp.name}_original.jar"/>
<property name="obf.jar" value="${webapp.name}.jar"/>
<property name="encryption.dir" value="${basedir}/encryption"/>
<property name="encrypted.webapp.jar.dir" value="${encryption.dir}/${webapp.name}_encrypted.jar"/>
<property name="encrypt.program.jar" value="${encryption.dir}/JarByteCodeEncrypt.jar"/>
<property name="shrinklog" value="${webapp.name}_shrinklog.xml"/>
<property name="renamelog" value="${webapp.name}_renamelog.xml"/>
<!-- 使用eclipse jdt进行编译,而不使用JDK编译
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
-->
<!-- 打印环境变量和属性赋值情况-->
<echoproperties/>

<target name="stop_tomcat" description="停止Tomcat">
<echo message="start tomcat..."/>
<exec executable="/bin/sh" os="Linux" dir="${catalina.home}/bin" failonerror="false">
<env key="PATH" path="${env.PATH}:"/>
<env key="CATALINA_HOME" path="${catalina.home}"/>
<arg value="stopsmartam.sh"/>
</exec>
<sleep seconds="2"/>
<echo message="end stop tomcat..."/>
</target>

<!-- 定义ant.svn.classpath,使用svn任务时可以使用-->
<path id="ant.svn.classpath">
<fileset dir="${ant.home}/lib">
<include name="*.jar"/>
</fileset>
</path>
<pathconvert pathsep="${line.separator}| |-- " property="echo.path.svn" refid="ant.svn.classpath">
</pathconvert>

<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="ant.svn.classpath"/>

<!-- 设置svn相关属性 -->
<svnSetting id="svn.setting" svnkit="true" username="${svn.username}" password="${svn.password}"
javahl="false"/>

<!-- show ant classpath jars -->
<target name="print_ant_classpath" depends="stop_tomcat" description="输出ant classpath">
<echo message="|-- ant svn classpath"/>
<echo message="| |"/>
<echo message="| |-- ${echo.path.svn}"/>
</target>

<!-- 删除之前的目录结构 -->
<target name="clear" description="清理旧文件" depends="print_ant_classpath">
<echo message="begin clean up directory..."/>
<delete dir="${build.config}" quiet="true"/>
<delete dir="${build.dir}" quiet="true"/>
<delete file="${dist.dir}/${webapp.name}.war" quiet="true"/>
<delete dir="${dist.dir}" quiet="true"/>
<delete dir="${svn.checkout.project}" quiet="true"/>
<delete dir="${svn.checkout.dir}" quiet="true"/>
<delete file="${catalina.home}/webapps/${webapp.name}.war" quiet="true"/>
<delete file="${catalina.home}/webapps/${webapp.name}" quiet="true"/>
<delete includeemptydirs="true" quiet="true">
<fileset dir="${catalina.home}/logs/" includes="**/*"/>
</delete>
<delete file="${encryption.dir}/${obf.jar}" quiet="true"/>
<delete file="${encrypted.webapp.jar.dir}" quiet="true"/>
<echo message="end clean up directory..."/>
</target>

<!-- 创建目录结构 -->
<target name="init" depends="clear" description="创建初始化目录结构">
<echo message="begin mkdir directory..."/>
<mkdir dir="${build.dir}/classes"/>
<mkdir dir="${dist.dir}"/>
<mkdir dir="${build.config}"/>
<mkdir dir="${svn.checkout.project}"/>
<mkdir dir="${svn.checkout.dir}"/>
<echo message="end mkdir directory..."/>
</target>

<!-- 检出代码 这里使用 export 不是checkout 二者区别 checkout会svn相关信息文件检出,export只是检出最新的文件 <export srcUrl="${svn.url}" destPath="${svn.checkout.project}" force="true"/>-->
<target name="checkout" depends="init" description="从svn下载源码">
<echo message="begin svn checkout..."/>
<svn refid="svn.setting">
<checkout url="${svn.url}" destPath="${svn.checkout.project}" force="true"/>
</svn>
<echo message="end svn checkout..."/>
</target>

<!-- 初始化classpath -->
<path id="project.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
<!-- 添加tomcat类路径 -->
<fileset dir="${catalina.home}/lib">
<include name="*.jar"/>
</fileset>
</path>

<!-- 初始化yguard classpath -->
<path id="yguard.classpath">
<!-- 添加yguard类路径 -->
<fileset dir="${svn.checkout.project}">
<include name="yguard.jar"/>
</fileset>
</path>

<!-- 编译java -->
<target name="compile" depends="checkout" description="编译java文件">
<echo message="begin compile..."/>
<javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" nowarn="on" source="1.7"
target="1.7" deprecation="true" debug="true" encoding="UTF-8" classpathref="project.classpath">
<compilerarg line="-Xlint:unchecked"/>
</javac>
<echo message="end compile..."/>
</target>

<!-- 将class文件打成 jar包 -->
<target name="pack" depends="compile">
<echo message="begin pack..."/>
<jar jarfile="${build.dir}/${app.jar}">
<fileset dir="${build.dir}/classes">
<exclude name="**/test/"/>
<include name="**/*.class"/>
</fileset>

<fileset dir="${src.dir}">
<include name="**/*.xml"/>
<include name="**/*.properties"/>
<include name="**/*.sql"/>
</fileset>

<manifest>
<!-- If this is an Applet or Web Start application, include
the proper attributes from https://docs.oracle.com/javase/8/docs/technotes/guides/jweb/index.html -->
<attribute name="Codebase" value="www.olm.com.cn"/>
<attribute name="Ant-Version" value="${ant.version}"/>
<attribute name="Built-JDK" value="${java.runtime.version} ${java.vendor}"/>
<!-- Who is building this jar? -->
<attribute name="Built-By" value="rocklei123"/>
<!-- Information about the program itself -->
<attribute name="Implementation-Vendor"
value="Beijing Orient LegendMarker Software Development Co.Ltd"/>
<attribute name="Implementation-Title" value="smartam"/>
<attribute name="Implementation-Version" value="3.2.0beta"/>
</manifest>
</jar>
<echo message="end pack..."/>
</target>

<!-- 混淆任务-->
<target depends="pack" name="yguard">
<echo message="begin yguard jar..."/>
<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask" classpathref="yguard.classpath"/>
<!-- the following can be adjusted to your needs -->
<yguard>
<inoutpair in="${build.dir}/${app.jar}" out="${build.dir}/${obf.jar}"/>
<externalclasses>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${catalina.home}/lib">
<include name="*.jar"/>
</fileset>
</externalclasses>

<shrink logfile="${build.dir}/${shrinklog}">
<keep>
<class classes="none" methods="public" fields="public">
<patternset>
<exclude name="com.xxxx"/>
</patternset>
</class>
</keep>
</shrink>
<rename logfile="${build.dir}/${renamelog}" conservemanifest="true">
<keep>
<class classes="private" methods="private" fields="private">
<patternset>
<!-- 不混淆的类-->
<include name="com.olm.**.action.**.*"/>
<include name="com.olm.**.impl.**.*"/>
<include name="com.olm.**.entity.**.*"/>
</patternset>
</class>
<package>
<patternset>
<include name="com.xxx.*"/>
</patternset>
</package>
</keep>
</rename>
</yguard>
<echo message="end yguard jar..."/>
</target>

<!-- 将混淆后的jar包加密 -->
<target name="encrypt" depends="yguard" description="将混淆后的jar包加密">
<echo message="begin encrypt jar..."/>
<copy file="${build.dir}/${obf.jar}" todir="${encryption.dir}"/>
<echo message="copy Obfuscator jar name of ${build.dir}/${obf.jar} to drictory ${encryption.dir}"/>
<java jar="${encrypt.program.jar}" failonerror="true" fork="true" maxmemory="128m">
<classpath>
<pathelement location="${encrypt.program.jar}"/>
</classpath>
</java>
<sleep seconds="5"/>
<echo message="end encrypt jar..."/>
</target>

<!-- 打成war包, 名称默认为 项目名 -->
<target name="war" depends="encrypt" description="将工程打成war包">
<echo message="begin war..."/>
<copy file="${encrypted.webapp.jar.dir}" todir="${lib.dir}"/>
<echo message="copy encrypted jar file name of ${encrypted.webapp.jar.dir} to directory ${lib.dir}..."/>
<war destfile="${dist.dir}/${webapp.name}.war" basedir="${webRoot.dir}" webxml="${webRoot.dir}/WEB-INF/web.xml">
<lib dir="${lib.dir}"/>
<fileset dir="${webRoot.dir}">
<include name="**/**.*"/>
<exclude name="**/test/"/>
<exclude name="${webRoot.dir}/WEB-INF/classes/"/>
<exclude name="**/*.jar"/>
<exclude name="**/*.class"/>
</fileset>
</war>
<echo message="end war..."/>
</target>

<!-- copy war包 tomcat的deploy目录 -->
<target name="deploy" depends="war" description="部署项目">
<echo message="begin deploy..."/>
<copy file="${dist.dir}/${webapp.name}.war" todir="${catalina.home}/webapps"/>
<echo message="end deploy..."/>
</target>

<target name="start_tomcat" depends="deploy">
<echo message="starting tomcat..."/>
<exec executable="/bin/sh" os="Linux" dir="${catalina.home}/bin" failonerror="true">
<env key="PATH" path="${env.PATH}:"/>
<env key="CATALINA_HOME" path="${catalina.home}"/>
<arg value="startup.sh"/>
</exec>
<sleep seconds="5"/>
<echo message="end start tomcat..."/>
</target>
</project>

实现效果

1545836156133

Build成功后可直接访问项目地址,查看最新的发布结果。

希望 大家手动敲一遍代码,会收获颇丰!

欢迎关注米宝窝,持续更新中,谢谢!

米宝窝 https://rocklei123.github.io/

https://blog.csdn.net/zhouleiblog

-------------本文结束感谢您的阅读-------------
欢迎持续关注米宝窝,定期更新谢谢! https://rocklei123.github.io/
欢迎持续关注我的CSDN https://blog.csdn.net/rocklei123
rocklei123的技术点滴
熬夜写博客挺辛苦的,生怕猝死,所以每当写博客都带着听诊器,心脏一有异响,随时按Ctrl+S。
rocklei123 微信支付

微信支付

rocklei123 支付宝

支付宝