乐于分享
好东西不私藏

浅谈assembly插件打包分发机制

浅谈assembly插件打包分发机制

      今天为什么要讲这个插件,它其实挺重要的,现在很多项目也在使用这个插件去做多环境的文件配置,如果一不小心就容易造成线上事故,你会发现你本地代码里面明明改了某个资源文件,但是到了其它环境就不生效,原因是你忽略了项目的打包机制。下面以一个案例讲解一下它的作用。
       首先我的项目是一个使用ssm框架的多模块项目,使用jetty容器部署web服务。父pom文件打包配置如下:
<build>        <finalName>${project.artifactId}</finalName><resources><resource><directory>src/main/resources</directory><filtering>true</filtering><!--				<excludes>					<exclude>**/disconf.properties</exclude>				</excludes>--></resource><resource><directory>src/main/assembly/${env.devMode}/resources</directory><filtering>true</filtering><excludes><exclude>**/disconf.properties</exclude></excludes></resource></resources></build>
     里面引进了Maven  Assembly 插件。项目打包的时候首先会打包src/main/resources资源下的所有文件,但排除disconf.properties。
 后面又会再打包一次src /main/assembly/${env.devMode}/resources目录下的资源文件,并排除该目录下的disconf.properties文件,这个时候假如该目录下有一个a.xml文件 和之前的打包的文件重名了,那么会覆盖掉前面的a.xml。这样的好处就是可以实现定制化配置,比如a.xml可能是你本地适用的一个文件,到了生产环境你的a.xml配置可能不一样,你就可以定义在assembly目录下,生产打包就会覆盖掉之前的文件。
        然后下面是我的web模块(resource资源存在该模块下)的pom文件打包配置如下:
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><appendAssemblyId>false</appendAssemblyId></configuration><executions><execution><id>make-assembly-dev</id><phase>package</phase><goals><goal>single</goal></goals><configuration><skipAssembly>false</skipAssembly><descriptors>								 <descriptor>src/main/assembly/assembly.xml</descriptor></descriptors><finalName>${project.artifactId}</finalName></configuration></execution></executions></plugin></plugins>        <profiles><profile><id>local</id><activation><activeByDefault>true</activeByDefault></activation><properties><env.devMode>local</env.devMode><skipAssemblyDEV>false</skipAssemblyDEV><skipAssemblySIT>true</skipAssemblySIT><skipAssemblyPROD>true</skipAssemblyPROD></properties></profile><profile><id>dev</id><activation></activation><properties><env.devMode>dev</env.devMode><skipAssemblyDEV>false</skipAssemblyDEV><skipAssemblySIT>true</skipAssemblySIT><skipAssemblyPROD>true</skipAssemblyPROD></properties></profile><profile><id>sit</id><activation></activation><properties><env.devMode>sit</env.devMode><skipAssemblyDEV>true</skipAssemblyDEV><skipAssemblySIT>false</skipAssemblySIT><skipAssemblyPROD>true</skipAssemblyPROD></properties></profile><profile><id>prod</id><activation></activation><properties><env.devMode>prod</env.devMode><skipAssemblyDEV>true</skipAssemblyDEV><skipAssemblySIT>true</skipAssemblySIT><skipAssemblyPROD>false</skipAssemblyPROD></properties></profile></profiles></build>
        其中结合Maven 的 Profile 配置,用于在不同环境(本地开发、开发环境、测试环境、生产环境)之间切换,控制构建行为。每个 profile 定义了一个环境,并设置三个 skipAssemblyXXX 参数,控制是否跳过对应环境的打包(assembly)操作。确保每个环境打包自己的assembly下的资源文件。
       项目目录结构示例如下:
src/main /
├── resources/                    # 公共资源
│   ├── application.properties
│   └── logback.xml
└── assembly/
    ├── local/resources/          # 本地环境专用
    │   └── application.properties
    ├── dev/resources/            # 开发环境专用
    │   └── application.properties
    ├── sit/resources/            # 测试环境专用
    │   └── application.properties
    └── prod/resources/           # 生产环境专用
        └── application.properties
         其中以sit下的asseembly文件为例:
<assembly><id>sit</id><formats><format>war</format></formats><includeBaseDirectory>false</includeBaseDirectory><fileSets><fileSet><directory>src/main/webapp</directory><outputDirectory>/</outputDirectory></fileSet><fileSet><directory>target/classes</directory><excludes><exclude>**/sysdemo.properties</exclude><exclude>**/logback.xml</exclude><exclude>**/jdbc.properties</exclude><exclude>**/disconf.properties</exclude><exclude>**/springmvc/spring-mvc.xml</exclude><exclude>**/spring/spring-context.xml</exclude><exclude>**/demo.properties</exclude><exclude>**/machineMaskdemo.properties</exclude></excludes><outputDirectory>/WEB-INF/classes</outputDirectory></fileSet><fileSet><directory>src/main/assembly/sit/resources</directory><outputDirectory>WEB-INF/classes</outputDirectory></fileSet></fileSets><dependencySets><dependencySet><useProjectArtifact>false</useProjectArtifact><outputDirectory>WEB-INF/lib</outputDirectory></dependencySet></dependencySets></assembly>
        该文件定义了一个打包机制,打包 target/classes 中的编译文件到 /WEB-INF/classes时排除了多个环境相关配置文件,这个时候就需要特别注意,比如里面的spring-context.xml文件,该文件被排除了,也就是打包的时候不会把resources目录下的文件打包。
        但是这里有个疑问,既然/assembly/sit/resources/spring/spring-context.xml 文件会覆盖之前的(所以改动该目录下的spring-context.xml 文件才会在sit生效),为什么上面还要排除?这里排除的好处是可以避免重复打包 – 减少不必要的文件处理。
        同时值得注意的是disconf.properties文件被排除,然后会使用/assembly下配置的disconf.properties文件。disconf是一个分布式文件配置中心,它也可以控制不同环境的文件配置,类似于nacos,但是它不能控制xml文件,所以才要结合assembly插件实现多环境配置文件的隔离。使用disconf.properties之后就可以不用在/assembly目录下定义被排除的其它properties文件了,因为我们可以放在disconf配置中心,实现远程读取,动态修改而不用重启服务。