maven-shade-plugin 插件简介

maven-shade-plugin简介

“This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.”,这句话简单的概述了maven-shade-plugin的作用,那就是作为一个超级jar包(uber-jar),在基本的管理依赖方面,需要支持更多的功能,如:

  • 1,将依赖的jar包打包时传入到当前classes目录(默认在lib文件下)。
  • 2,将依赖的jar包重命名,比如你在当前项目中依赖了tomcat-9.0的jar包,但是需求是需要项目在tomcat-8.5中允许,在出现版本冲突的时候,你可以使用maven-shade-plugin将你依赖的tomcat-9.0的jar包重命名并添加至你的classes目录下。

maven-shade-plugin 的使用

对jar包中的依赖进行更详细的筛选

1、对jar包进行添加或排除
<project>
 ...
   <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <artifactSet>
                <excludes>
                  <exclude>classworlds:classworlds</exclude>
                  <exclude>junit:junit</exclude>
                  <exclude>jmock:*</exclude>
                  <exclude>*:xml-apis</exclude>
                  <exclude>org.apache.maven:lib:tests</exclude>
                  <exclude>log4j:log4j:jar:</exclude>
                </excludes>
              </artifactSet>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>
2、对jar包里面的类进行添加或排除
<project>
      ...
	  <build>
	    <plugins>
	      <plugin>
	        <groupId>org.apache.maven.plugins</groupId>
	        <artifactId>maven-shade-plugin</artifactId>
	        <version>3.2.1</version>
	        <executions>
	          <execution>
	            <phase>package</phase>
	            <goals>
	              <goal>shade</goal>
	            </goals>
	            <configuration>
	              <filters>
	                <filter>
	                  <artifact>junit:junit</artifact>
	                  <includes>
	                    <include>junit/framework/**</include>
	                    <include>org/junit/**</include>
	                  </includes>
	                  <excludes>
	                    <exclude>org/junit/experimental/**</exclude>
	                    <exclude>org/junit/runners/**</exclude>
	                  </excludes>
	                </filter>
	                <filter>
	                  <artifact>*:*</artifact>
	                  <excludes>
	                    <exclude>META-INF/*.SF</exclude>
	                    <exclude>META-INF/*.DSA</exclude>
	                    <exclude>META-INF/*.RSA</exclude>
	                  </excludes>
	                </filter>
	              </filters>
	            </configuration>
	          </execution>
	        </executions>
	      </plugin>
	    </plugins>
	  </build>
	  ...
</project>

3、自动移除没有使用的依赖
<project>
      ...
	  <build>
	    <plugins>
	      <plugin>
	        <groupId>org.apache.maven.plugins</groupId>
	        <artifactId>maven-shade-plugin</artifactId>
	        <version>3.2.1</version>
	        <executions>
	          <execution>
	            <phase>package</phase>
	            <goals>
	              <goal>shade</goal>
	            </goals>
	            <configuration>
	              <minimizeJar>true</minimizeJar>
	            </configuration>
	          </execution>
	        </executions>
	      </plugin>
	    </plugins>
	  </build>
	  ...
</project>
4、组合使用
   <project>
          ...
		  <build>
		    <plugins>
		      <plugin>
		        <groupId>org.apache.maven.plugins</groupId>
		        <artifactId>maven-shade-plugin</artifactId>
		        <version>3.2.1</version>
		        <executions>
		          <execution>
		            <phase>package</phase>
		            <goals>
		              <goal>shade</goal>
		            </goals>
		            <configuration>
		              <minimizeJar>true</minimizeJar>
		              <filters>
		                <filter>
		                   <artifact>log4j:log4j</artifact>
		                   <includes>
		                       <include>**</include>
		                   </includes>
		                </filter>
		                <filter>
		                   <artifact>commons-logging:commons-logging</artifact>
		                   <includes>
		                       <include>**</include>
		                   </includes>
		                </filter>
		              </filters>            
		            </configuration>
		          </execution>
		        </executions>
		      </plugin>
		    </plugins>
		  </build>
		  ...
   </project>

设置编译后的classes目录位置

如果需要将某个jar用作其他项目的依赖项,但是又因为其依赖项中直接包含类,因此会由于类路径上的重复类而导致类加载冲突。 为了解决这个问题,可以重新定位shade组件中包含的类,以创建其字节码的私有副本:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <relocations>
                <relocation>
                  <pattern>org.codehaus.plexus.util</pattern>
                  <shadedPattern>org.shaded.plexus.util</shadedPattern>
                  <excludes>
                    <exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
                    <exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
                  </excludes>
                </relocation>
              </relocations>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

当然,我们也可以进一步的缩小其作用范围:

<project>
  ...
                <relocation>
                  <pattern>org.codehaus.plexus.util</pattern>
                  <shadedPattern>org.shaded.plexus.util</shadedPattern>
                  <includes>
                    <include>org.codehaud.plexus.util.io.*</include>
                  </includes>
                </relocation>
  ...
</project>

修改打包后默认的shade文件的命名

默认情况下,shade插件会覆盖基于项目的jar包,而生成包含所有依赖的jar包。但有时需要原始的jar包和shade后的jar包同时被部署,可以配置如下:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <shadedArtifactAttached>true</shadedArtifactAttached>
              <shadedClassifierName>jackofall</shadedClassifierName> <!-- 名称会作为后缀在shade构件jar包后 -->
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

可执行的jar包

想要生成一个可以执行的jar包,就需要指定当前应用程序下main类的位置:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>org.sonatype.haven.HavenCli</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

此代码段通过配置特殊的资源转换器在带shade插件的的 JAR 中的 MANIFEST.MF 中设置Main-Class条目。 其他条目也可以通过 manifestEntries 部分中的键值对添加到MANIFEST.MF

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>org.sonatype.haven.ExodusCli</Main-Class>
                    <Build-Number>123</Build-Number>
                  </manifestEntries>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

常见的资源转换器

ManifestResourceTransformer

ManifestResourceTransformer 允许替换MANIFEST.MF中的现有条目并添加新条目:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>${app.main.class}</Main-Class>
                    <X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK>
                    <X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK>
                  </manifestEntries>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>
IncludeResourceTransformer

IncludeResourceTransformer 允许以给定名称将项目文件包含在包中。
例如,以下示例在包中将README.txt作为META-INF目录中的README包含在内:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
                    <resource>META-INF/README</resource>
                    <file>README.txt</file>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

DontIncludeResourceTransformer

DontIncludeResourceTransformer允许以指定给定值结尾的方式排除资源。
例如,以下示例排除了所有以.txt结尾的资源。

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
                    <resource>.txt</resource>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

AppendingTransformer

某些jar包含具有相同文件名的其他资源(例如属性文件)。 为避免覆盖,您可以选择通过将它们的内容附加到一个文件中来合并它们。 一个很好的例子是同时聚合spring-context和plexus-spring jars。 它们都具有META-INF / spring.handlers文件,Spring使用该文件来处理XML模式名称空间。 您可以使用AppendingTransformer合并具有该特定名称的所有文件的内容,如下所示:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                  <resource>META-INF/spring.handlers</resource>
                </transformer>
                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                  <resource>META-INF/spring.schemas</resource>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

XmlAppendingTransformer

对于xml文件,您可以使用XmlAppendingTransformer:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                  <resource>META-INF/magic.xml</resource>
                  <!-- Add this to enable loading of DTDs
                  <ignoreDtd>false</ignoreDtd>
                  -->
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

PluginXmlResourceTransformer

提供某些接口的实现的JAR文件通常带有META-INF/services/目录,该目录将接口映射到其实现类以供服务定位器查找。 要重新定位这些实现类的类名,并将同一接口的多个实现合并到一个服务条目中,可以使用ServicesResourceTransformer:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

maven-shade-plugin原理介绍

原理是利用了ASM框架来修改字节码:

static class RelocatorRemapper
        extends Remapper
    {

        private final Pattern classPattern = Pattern.compile( "(\\[*)?L(.+);" );
    
        List<Relocator> relocators;
    
        RelocatorRemapper( List<Relocator> relocators )
        {
            this.relocators = relocators;
        }
    
        public boolean hasRelocators()
        {
            return !relocators.isEmpty();
        }
    
        public Object mapValue( Object object )
        {
            if ( object instanceof String )
            {
                String name = (String) object;
                String value = name;
    
                String prefix = "";
                String suffix = "";
    
                Matcher m = classPattern.matcher( name );
                if ( m.matches() )
                {
                    prefix = m.group( 1 ) + "L";
                    suffix = ";";
                    name = m.group( 2 );
                }
    
                for ( Relocator r : relocators )
                {
                    if ( r.canRelocateClass( name ) )
                    {
                        value = prefix + r.relocateClass( name ) + suffix;
                        break;
                    }
                    else if ( r.canRelocatePath( name ) )
                    {
                        value = prefix + r.relocatePath( name ) + suffix;
                        break;
                    }
                }
    
                return value;
            }
    
            return super.mapValue( object );
        }
    
        public String map( String name )
        {
            String value = name;
    
            String prefix = "";
            String suffix = "";
    
            Matcher m = classPattern.matcher( name );
            if ( m.matches() )
            {
                prefix = m.group( 1 ) + "L";
                suffix = ";";
                name = m.group( 2 );
            }
    
            for ( Relocator r : relocators )
            {
                if ( r.canRelocatePath( name ) )
                {
                    value = prefix + r.relocatePath( name ) + suffix;
                    break;
                }
            }
    
            return value;
        }
    
    }



(END)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catoop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值