浅谈Java项目打包方式

 


大家都知道在Java里面开发一个web服务非常繁琐,首先需要各种框架,各种配置,完事之后,需要打成一个war包,最后需要一个servlet容器,Tomcat或者Jetty,Jboss,来运行发布,同样的事情,你会发现在其他的语言中,是非常简单的,比如python里面的Django或者tornado,ruby里面的rails等,随着近年来微服务越来越流行,一个简单,强大,灵活,易配置,易开发的web服务迫在眉睫,而它就是Spring Boot,统一了Java web开发的各个需要的框架,提供了大而全的功能支持。 这里就不在具体介绍了,有需要的朋友,可以看散仙写过的几篇关于它的文章http://qindongliang.iteye.com/blog/2205633。 


Spring Boot为什么容易开发微服务?当然它也不仅仅限于微服务,它还可以与Dubbo集成,实现企业级服务化,因为Spring Boot内嵌了servlet容器,发布服务时,仅仅需要一个jar包,所有有关的依赖全部在这个jar包中,所以不需要你额外下载一个tomcat或者jetty来运行服务,这个jar包,拷贝到任何含有JDK的环境的机器上,都可以任意运行,除此之外,因为仅仅只有一个jar包,所以与Jekins和Docker的集成都非常方便,这种方式以后会逐渐流行,而以war包+外置容器的发布方式散仙预测以后会逐渐没落,这里就不在具体介绍这种打包方式了。 

接着上面谈,由于所有的东西,都在这个jar包中,当你依赖越来越多时,这个jar包的体积,就会上升的厉害,在我们的一个应用场景中,集成了dubbo,redis,solr,hadoop,hbase,最后一个jar包体积,快接近100M了,不过,体积大到是次要的,只要服务能正常运行,可以忽略这个小缺点,之后启动,停止脚本也非常简洁: 
启动脚本: 

Shell代码   收藏代码
  1. #!/bin/bash  
  2. JAVA_HOME=/tool/server/jdk  
  3. CLASSPATH=.:$JAVA_HOME  
  4. PATH=$JAVA_HOME/bin:$PATH  
  5. export JAVA_HOME CLASSPATH PATH  
  6.   
  7. nohup  java -jar   work.jar    &>task.log &   echo $! >pid&   


停止脚本: 

Shell代码   收藏代码
  1. kill -9 `cat pid`  


上面散仙谈到的spring boot能够封装所有的依赖进入一个jar包中,前提是需要提前配置好各个运行参数,然后编译打包,运行这个jar,假如在已经发布到服务器上,我想改一些参数配置,应该如何操作呢? 这时候就会发现面对一个jar,你无法干任何事,除非回到maven工程中,改里面的配置参数,然后重新打包,接着用Jenkins发布到docker里面,假如这时候,你上传到服务器的网速非常慢,几十kb/秒,偏偏你又有一个100M的jar,还不得发布到猴年马月,这里说的不夸张,是实际开发中可能遇到的一种情况。 


那么如何比较好的处理这种问题呢?其实也不难,在打包的时候,分离工程,形成一个基本的目录如下: 

Java代码   收藏代码
  1. bin/    //存放处理脚本  
  2. lib/    //存放jar包  
  3. conf/ //存放配置文件  
  4. logs/ //存放log  


看到上面的这个目录,大伙是不是有种回到了Ant的年代的感觉呢,其实不然在Maven中,我们可以使用maven-assembly-plugin插件,来完成更优雅的打包 
方式,仅需要项目中,改动下面两个部分即可完成: 

(1)在pom文件中,添加如下插件: 

Xml代码   收藏代码
  1. <build>  
  2.      <plugins>  
  3.   
  4.          <plugin>  
  5.              <groupId>org.apache.maven.plugins</groupId>  
  6.              <artifactId>maven-assembly-plugin</artifactId>  
  7.              <configuration>  
  8.                  <!--<appendAssemblyId>true</appendAssemblyId>-->  
  9.                  <descriptors> <!--描述文件路径-->  
  10.                      <descriptor>src/main/assemble/package.xml</descriptor>  
  11.                  </descriptors>  
  12.              </configuration>  
  13.              <executions>  
  14.                  <execution>  
  15.                      <id>make-zip</id>  
  16.                      <!-- 绑定到package生命周期阶段上 -->  
  17.                      <phase>package</phase>  
  18.                      <goals>  
  19.                          <!-- 绑定到package生命周期阶段上 -->  
  20.                          <goal>single</goal>  
  21.                      </goals>  
  22.   
  23.                  </execution>  
  24.              </executions>  
  25.          </plugin>  
  26.   
  27.      </plugins>  
  28.   
  29.  </build>  


(2) 在main下面新建一个assemble文件夹,并在该文件夹下新建一个package.xml文件,内容如下: 

Xml代码   收藏代码
  1. <?xml version="1.0"?>  
  2. <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"  
  3.           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.           xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">  
  5.   
  6.     <!--项目标识,设置的话,生成后的zip文件会加上此后缀-->  
  7.     <id></id>  
  8.     <!--打包格式-->  
  9.     <formats>  
  10.         <format>zip</format>  
  11.     </formats>  
  12.     <!--是否包含根目录文件夹-->  
  13.     <includeBaseDirectory>true</includeBaseDirectory>  
  14.   
  15.     <fileSets>  
  16.   
  17.         <!--<fileSet>-->  
  18.         <!--<directory>${project.basedir}\src\main\resources</directory>-->  
  19.         <!--<outputDirectory>\</outputDirectory>-->  
  20.         <!--<includes>-->  
  21.         <!--<include>some/path</include>-->  
  22.         <!--</includes>-->  
  23.         <!--<excludes>-->  
  24.         <!--<exclude>some/path1</exclude>-->  
  25.         <!--</excludes>-->  
  26.         <!--</fileSet>-->  
  27.   
  28.         <!--自定义文件描述集-->  
  29.         <fileSet>  
  30.             <!--自定义脚本目录打包-->  
  31.             <directory>${project.basedir}\src\main\bin</directory>  
  32.             <outputDirectory>\bin</outputDirectory>  
  33.             <includes>  
  34.                 <include>*.*</include>  
  35.             </includes>  
  36.             <!--设置权限-->  
  37.             <fileMode>0755</fileMode>  
  38.         </fileSet>  
  39.   
  40.   
  41.         <!--<fileSet>-->  
  42.             <!--<!&ndash;外部配置文件打包&ndash;>-->  
  43.             <!--<directory>${project.basedir}\src\main\config</directory>-->  
  44.             <!--<outputDirectory>\config</outputDirectory>-->  
  45.             <!--<includes>-->  
  46.                 <!--<include>*.*</include>-->  
  47.             <!--</includes>-->  
  48.             <!--<fileMode>0644</fileMode>-->  
  49.         <!--</fileSet>-->  
  50.   
  51.     </fileSets>  
  52.   
  53.     <dependencySets>  
  54.   
  55.         <dependencySet>  
  56.             <useProjectArtifact>true</useProjectArtifact>  
  57.             <outputDirectory>lib</outputDirectory>  
  58.             <!-- 将scope为runtime的依赖包打包到lib目录下。 -->  
  59.             <scope>runtime</scope>  
  60.         </dependencySet>  
  61.     </dependencySets>  
  62.   
  63. </assembly>  


当然这种启动,停止脚本,稍微复杂点,需要把所有的jar包和配置文件cp到一个JVM里面,然后执行: 
启动脚本: 

Shell代码   收藏代码
  1. cs=`echo /ROOT/tmp/z_check_hbase/lib/*jar | sed 's/ /:/g'`  
  2. #配置文件的目录  
  3. conf="$cdir/conf:"  
  4. #追加进入cp中  
  5. cs=$cs$conf  
  6. #打印  
  7. echo $cs  
  8. #执行  
  9. nohup java -cp  $cs  com.tools.HbaseDaoImpl   &>/dev/null  &   echo $! >pid&  

停止脚本: 
Shell代码   收藏代码
  1. kill -9 `cat pid`  




总结: 

对比spring boot中的单一jar的打包方式,这种方式,则将jar包和配置分离,我们可以随时改配置参数,然后重新启动,这样做灵活性大大提高了,而且在远程传入服务器时,除了第一次需要传所有的依赖文件,以后,改动代码后,只需要传主jar即可,因为依赖的jar基本都不会变,而当使用单一的jar时,任何改动都需要上传整个jar。这在jar包体积比较大时,网速比较慢时,是非常耗时的,但由于分离了配置文件和jar,复杂性会稍微提高,当然这算不了什么,因为我们可以用zip或者tar.gz将它压缩成一个整体,然后可以部署到任意机器上。 


 

在Java里面,除了Spring Boot外,另外一个比较给力的Web服务框架就是Scala的Play2了,目前最新版本是2.5,采用sbt管理依赖,引入Netty实现高性能http服务,不再维持会话状态,如果你需要会话状态,就自己采用redis或者memcache等来实现,它打包后会自动生成压缩包,压缩包里面包含了分离的lib和conf以及win和linux部署脚本,这一点与我们上面说的第二种方式,大致上是一致的,对上线发布非常友好,当然这里并没有绝对的好坏之分: 

单一jar的打包方式总体来说对微服务比较友好 
分离jar的打包方式总体来说对企业级大型服务比较友好 

当然你也可以混搭,只要是适合自己场景的方式,就是最好,最优雅的方式。 


有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。 
技术债不能欠,健康债更不能欠, 求道之路,与君同行。 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值