写在前面
本文看下maven的optional选项的作用和用法。
1:什么作用
考虑这样的场景,A依赖B,B依赖C,正常的按照依赖的传递性,A也会间接的依赖C,但是在一些特定的场景中项目A只希望依赖B,而不依赖C,此时就需要使用到optional选项。具体使用也比较简单,只需要在C的对应依赖GAV中增加<optional>true</optional>
就行了。
2:实战例子
我们使用maven的父子项目首先创建项目A,其POM如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>untitled5656</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>A</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<!-- <optional>true</optional>-->
</dependency>
</dependencies>
</project>
可以看到我们依赖了fastjson,并且注释掉了optional(默认false)
,接着处理项目B,在其pom中依赖项目A:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>untitled5656</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>B</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
接着执行命令mvn clean install dependency:tree
:
PS D:\netty-sourcecode\untitled5656> mvn clean install dependency:tree
...
[INFO] org.example:B:jar:1.0-SNAPSHOT
[INFO] +- cn.hutool:hutool-all:jar:5.8.26:compile
[INFO] \- org.example:A:jar:1.0-SNAPSHOT:compile
[INFO] \- com.alibaba:fastjson:jar:1.2.83:compile
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.410 s
[INFO] Finished at: 2024-11-15T11:38:20+08:00
[INFO] ------------------------------------------------------------------------
可以看到此时项目B不仅仅依赖了项目A,还传递依赖了项目A直接依赖的fastjson,如果是不需要依赖fastjson,则可以修改jackson pom为如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<optional>true</optional>
</dependency>
即增加<optional>true</optional>
,重新导入依赖后,再执行命令mvn clean install dependency:tree
:
PS D:\netty-sourcecode\untitled5656> mvn clean install dependency:tree
[INFO] Scanning for projects...
...
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ B ---
[INFO] org.example:B:jar:1.0-SNAPSHOT
[INFO] +- cn.hutool:hutool-all:jar:5.8.26:compile
[INFO] \- org.example:A:jar:1.0-SNAPSHOT:compile
[INFO] ------------------------------------------------------------------------
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.324 s
[INFO] Finished at: 2024-11-15T11:44:23+08:00
[INFO] ------------------------------------------------------------------------
此时项目A的jackson就没有被传递依赖了。
3:在netty中的应用
netty中的日志工具类,会根据我们项目中具体引入了哪种jdk的相关jar而进行动态的选择日志实现,如下:
// io.netty.util.internal.logging.InternalLoggerFactory#newDefaultFactory
private static InternalLoggerFactory newDefaultFactory(String name) {
InternalLoggerFactory f = useSlf4JLoggerFactory(name);
if (f != null) {
return f;
}
f = useLog4J2LoggerFactory(name);
if (f != null) {
return f;
}
f = useLog4JLoggerFactory(name);
if (f != null) {
return f;
}
return useJdkLoggerFactory(name);
}
其中以useSlf4JLoggerFactory为例看下:
private static InternalLoggerFactory useSlf4JLoggerFactory(String name) {
try {
InternalLoggerFactory f = new Slf4JLoggerFactory(true);
f.newInstance(name).debug("Using SLF4J as the default logging framework");
return f;
} catch (LinkageError ignore) {
return null;
} catch (Exception ignore) {
// We catch Exception and not ReflectiveOperationException as we still support java 6
return null;
}
}
这里当运行环境中有对应的类时就会返回正常的实例,否则发生异常返回null。这里的日志相关的依赖就都是optional的,因为使用common包的项目并不一定需要这些依赖,就算需要的话,自己单独引入就可以了,如下:
而因为common中引入了,所以common本身的编译肯定是没有问题的,只不过依赖common的项目不会传递依赖这些log相关的依赖了。
写在后面
参考文章列表
maven之如何查看依赖树 。