浅谈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/${env.devMode}/assembly.xml</descriptor>-->
								 <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配置中心,实现远程读取,动态修改而不用重启服务。

相关推荐
历程里程碑2 天前
Protobuf vs JSON vs XML:小白该怎么选?
xml·大数据·数据结构·elasticsearch·链表·搜索引擎·json
那个失眠的夜3 天前
Mybatis延迟加载策略
xml·java·数据库·maven·mybatis
mfxcyh3 天前
基于xml、注解、JavaConfig实现spring的ioc
xml·java·spring
vortex53 天前
SOAP 协议中的 XML 外部实体注入(XXE)漏洞
xml·网络安全·渗透测试
Dxy12393102163 天前
Python如何对XML进行格式化
xml·python
2501_930707784 天前
使用C#代码将 HTML 转换为 PDF、XPS 和 XML
xml·pdf
研來如此9 天前
tinyxml2 常用读取接口对照表
xml·c++·tinyxml2
pupudawang10 天前
使用 Logback 的最佳实践:`logback.xml` 与 `logback-spring.xml` 的区别与用法
xml·spring·logback
jf加菲猫10 天前
第10章 数据处理
xml·开发语言·数据库·c++·qt·ui