关于ConditionalOnClass注解

1. pom文件<optional>标签

在Java开发中,大家肯定在pom文件中添加过依赖(现在没有,以后也肯定会有的),不知道大家对<optional>标签的了解有多少,或者是你没看下面内容,都不知道optional单词应该放在什么地方,没关系我会讲,听不懂还可以搜索别的优质博客。

<optional>标签在pom文件中长这样:

<dependency>
  <groupId>com.handsometaoa</groupId>
  <artifactId>sms-utool</artifactId>
  <version>1.0-SNAPSHOT</version>
  <optional>true</optional> <!-- 在这里 -->
</dependency>

它的作用是:当其他模块依赖当前模块时,不会传递依赖 optional 标签值为true的依赖文件,可结合下图理解:

B模块依赖C模块,并提供了BHelloUtils类,其中调用了C模块CHelloUtils的cSayHello方法,并注意(加粗)B模块pom文件中C依赖项的optional标签值为true

现在A模块依赖B模块,当调用BHelloUtils中bSayHello方法,程序会进行报错,提示找不到CHelloUtils,这里就验证了optional的作用。

那我们应该如何调整程序?在A模块pom文件添加C依赖。

2. optional hutool应用实例

空口无凭,Hutool 工具包实现了很多好用的工具,他的扩展工具包就依赖很多了第三方工具包,例如:

2.1 验证

怎么验证?拿emoji举例,没添加emoji-java依赖,EmojiUtil会爆红(找不到依赖项)。

为什么我们使用hutool工具时,没添加emoji-java也没显示错误?由于Java是动态加载,在未使用时不会报错。

2.2 设计原因

Hutool开发者考虑到扩展中的内容我们一般不会用到,假如Hutool pom中为默认或者<optional>false</optional>,当我们引入hutool工具,会相应引入额外的其他依赖(本质上不会使用),也可能会导致依赖冲突(hutool 中依赖版本为1.1.1,自己项目中版本为 1.0.9)。

3. ConditioalOnClass

ConditioalOnClass:就是当前类路径下存在该类,才会使标有该注解的类或方法生效

3.1 测试代码结构总览


sms-unite-sdk中配置类可以这样写,就能实现阿里云、腾讯云短信二选一。

@Configuration
public class SmsConfig {

    @Bean
    @ConditionalOnClass(name = "com.aliyun.sms.SmsServiceImpl")
    public SmsService ailiyunSmsService() {
        System.out.println("aliyun smsService init");
        return new com.aliyun.sms.SmsServiceImpl();
    }

    @Bean
    @ConditionalOnMissingBean(SmsService.class)
    @ConditionalOnClass(name = "com.tencent.sms.SmsServiceImpl")
    public SmsService tencentSmsService() {
        System.out.println("tx smsService init");
        return new com.tencent.sms.SmsServiceImpl();
    }

}

4. 关于Spring 自动装配

2.7.x之前:resources 下增加META-INF文件夹,创建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.handsometaoa.config.SmsConfig

2.7.x之后:resources 下增加META-INF文件夹,在其下创建spring文件夹,最后创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件

com.handsometaoa.config.SmsConfig

为了兼容,可以同时写:

在pom文件中

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>2.7.18</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${spring-boot.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-expression</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
            <optional>true</optional> <!-- 注意这里,用户引用此模块,spring会自动使用用户的版本 --> 
        </dependency>
        
        <!-- 省略其他  -->
    </dependencies>

5. Demo代码

https://github.com/handsometaoa/condition_on_class-demo (可结合代码、本地执行进行理解)

posted @ 2024-05-13 21:43  帅气的涛啊  阅读(67)  评论(0编辑  收藏  举报