欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解密Spring?Boot深入理解條件裝配與條件注解

 更新時(shí)間:2024年06月13日 15:32:52   作者:憶~遂愿  
條件注解是一種特殊的注解,用于標(biāo)記在配置類、組件類或方法上,它們根據(jù)某些條件的結(jié)果來決定是否應(yīng)用相應(yīng)的配置或組件,這篇文章主要介紹了解密Spring?Boot深入理解條件裝配與條件注解,需要的朋友可以參考下

一、條件裝配概述

1.1 條件裝配的基本原理

條件裝配的基本原理是根據(jù)特定的條件來決定是否應(yīng)用特定的配置或組件。在 Spring Boot 中,條件裝配是通過條件注解來實(shí)現(xiàn)的。

條件注解是一種特殊的注解,用于標(biāo)記在配置類、組件類或方法上。它們根據(jù)某些條件的結(jié)果來決定是否應(yīng)用相應(yīng)的配置或組件。

條件注解的基本原理

  • 條件判斷:Spring 在處理配置類或組件時(shí),會(huì)對(duì)標(biāo)記了條件注解的類或方法進(jìn)行條件判斷。
  • 條件匹配:條件注解中定義的條件匹配器會(huì)根據(jù)特定的條件,如類路徑是否存在、Bean 是否存在、屬性是否被設(shè)置等,對(duì)環(huán)境進(jìn)行判斷,如果條件滿足則返回 true,否則返回 false。
  • 條件注解處理器:Spring 容器會(huì)使用條件注解處理器來處理?xiàng)l件注解,根據(jù)條件匹配的結(jié)果來決定是否應(yīng)用相應(yīng)的配置或組件。
  • 應(yīng)用配置或組件:根據(jù)條件注解的處理結(jié)果,Spring 容器會(huì)決定是否應(yīng)用相應(yīng)的配置或組件。如果條件滿足,則進(jìn)行相應(yīng)的配置或組件的注冊(cè)和初始化;如果條件不滿足,則忽略該配置或組件。

1.2 條件裝配的作用

條件裝配的作用在于根據(jù)特定的條件來決定是否應(yīng)用特定的配置或組件,從而實(shí)現(xiàn)靈活性和可配置性。

條件裝配實(shí)現(xiàn)的作用

  • 環(huán)境適配:通過條件裝配,可以根據(jù)當(dāng)前的運(yùn)行環(huán)境(如開發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境)或者配置(如不同的數(shù)據(jù)庫、不同的服務(wù)提供商)來動(dòng)態(tài)地選擇合適的配置或組件,從而使應(yīng)用程序適應(yīng)不同的環(huán)境。
  • 可插拔性:條件裝配可以根據(jù)應(yīng)用程序的需求動(dòng)態(tài)地選擇性地應(yīng)用不同的配置或組件,使得應(yīng)用程序的功能可以根據(jù)需求進(jìn)行擴(kuò)展或者替換,從而增強(qiáng)了應(yīng)用程序的可插拔性和可擴(kuò)展性。
  • 簡(jiǎn)化配置:通過條件裝配,可以根據(jù)特定的條件自動(dòng)地應(yīng)用相應(yīng)的配置或組件,而無需手動(dòng)配置或編寫復(fù)雜的條件判斷邏輯,從而簡(jiǎn)化了配置過程,提高了配置的易用性和可維護(hù)性。
  • 優(yōu)化性能:通過條件裝配,可以根據(jù)特定的條件選擇性地應(yīng)用相應(yīng)的配置或組件,避免不必要的資源消耗,從而優(yōu)化了應(yīng)用程序的性能和資源利用率。

二、常用注解

2.1 @ConditionalOnClass

@ConditionalOnClass 是 Spring Boot 中的一個(gè)條件注解,用于在類路徑中存在指定的類時(shí)才會(huì)應(yīng)用相應(yīng)的配置。

定義了一個(gè)靈活的條件注解 ConditionalOnClass,它可以根據(jù)類路徑中特定類的存在與否來決定是否應(yīng)用相應(yīng)的配置或組件。

示例和用法說明

/**
 * 只有當(dāng)應(yīng)用程序的類路徑中存在 RedisTemplate 類時(shí),RedisConfiguration 類中定義的 redisTemplate() 方法才會(huì)被注冊(cè)為 Bean,并被 Spring 容器管理
 * 如果類路徑中不存在 RedisTemplate 類,則該配置類中的 Bean 將被忽略
 */
@Configuration
@ConditionalOnClass({org.springframework.data.redis.core.RedisTemplate.class})
public class RedisConfiguration {
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 配置 RedisTemplate 的相關(guān)屬性
        return redisTemplate;
    }
}

2.2 @ConditionalOnBean

@ConditionalOnBean 是 Spring Framework 中的一個(gè)條件注解,它的作用是在容器中存在指定的 Bean 時(shí),才會(huì)應(yīng)用相應(yīng)的配置或組件。如果指定的 Bean 不存在,則該配置或組件將被忽略。

定義了一個(gè)具有多個(gè)屬性的注解 ConditionalOnBean,可以用于指定條件判斷所依賴的類、名稱、注解等信息,以及搜索依賴 Bean 的策略和泛型容器中的參數(shù)化類型。

示例和用法說明

基本用法

/**
 * MyService 類被標(biāo)記為 @ConditionalOnBean(MyBean.class),這意味著只有當(dāng)容器中存在 MyBean 類型的 Bean 時(shí),MyService 才會(huì)被創(chuàng)建并添加到容器中
 */
@Configuration
public class MyConfiguration {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
    @ConditionalOnBean(MyBean.class)
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

多個(gè) Bean 的情況

/**
 * MyService 類被標(biāo)記為 @ConditionalOnBean({MyBean.class, AnotherBean.class}),這意味著只有當(dāng)容器中同時(shí)存在 MyBean 和 AnotherBean 類型的 Bean 時(shí),MyService 才會(huì)被創(chuàng)建并添加到容器中
 */
@Configuration
public class MyConfiguration {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
    @Bean
    public AnotherBean anotherBean() {
        return new AnotherBean();
    }
    @ConditionalOnBean({MyBean.class, AnotherBean.class})
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

使用名稱來指定 Bean

/**
 * MyService 類被標(biāo)記為 @ConditionalOnBean(name = {"myBean", "anotherBean"}),這意味著只有當(dāng)容器中同時(shí)存在名稱為 "myBean" 和 "anotherBean" 的 Bean 時(shí),MyService 才會(huì)被創(chuàng)建并添加到容器中
 */
@Configuration
public class MyConfiguration {
    @Bean(name = "myBean")
    public MyBean myBean() {
        return new MyBean();
    }
    @Bean(name = "anotherBean")
    public AnotherBean anotherBean() {
        return new AnotherBean();
    }
    @ConditionalOnBean(name = {"myBean", "anotherBean"})
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

2.3 @ConditionalOnProperty

@ConditionalOnProperty 注解是 Spring Framework 中的條件注解之一,用于基于配置屬性的存在與否來決定是否應(yīng)用某個(gè)配置。

定義了一個(gè)具有多個(gè)屬性的注解 ConditionalOnProperty,它可以用于根據(jù)配置文件中的屬性值來決定是否應(yīng)用某個(gè)配置。

示例和說明

/**
 * @ConditionalOnProperty 注解指定了一個(gè)名為myapp.feature.enabled 的屬性,當(dāng)這個(gè)屬性存在并且其值為"true"時(shí),MyFeatureConfiguration 配置類中的配置會(huì)生效
 * havingValue 參數(shù)指定了期望的屬性值,如果沒有指定havingValue,則默認(rèn)匹配任何非空值
 * matchIfMissing 參數(shù)指定了當(dāng)配置文件中未設(shè)置該屬性時(shí),是否應(yīng)該匹配。如果設(shè)置為 true,則表示當(dāng)屬性不存在時(shí)也匹配,這樣可以設(shè)置默認(rèn)行為
 */
@Configuration
@ConditionalOnProperty(
    name = "myapp.feature.enabled",
    havingValue = "true",
    matchIfMissing = true
)
public class MyFeatureConfiguration {
}
myapp.feature.enabled=true

2.4 @ConditionalOnExpression

@ConditionalOnExpression 是 Spring 框架中的一個(gè)條件注解,在應(yīng)用配置時(shí)根據(jù) SpEL表達(dá)式的結(jié)果來決定是否進(jìn)行配置。它允許我們使用更靈活的表達(dá)式來控制配置的條件。

定義了一個(gè)具有一個(gè)屬性的注解 ConditionalOnExpression,它可以根據(jù) SpEL 表達(dá)式的結(jié)果來決定是否應(yīng)用某個(gè)配置。

示例和說明:

/**
 * 檢查配置文件中的 my.config.enabled 屬性是否等于 'true'
 * 如果等于 'true',則表達(dá)式結(jié)果為 true`,MyBean 實(shí)例將會(huì)被創(chuàng)建
 * 否則,表達(dá)式結(jié)果為 false,配置將被忽略,不會(huì)創(chuàng)建 MyBean 實(shí)例
 */
@Configuration
public class MyConfig {
    @Bean
    @ConditionalOnExpression("#{environment.getProperty('my.config.enabled') == 'true'}")
    public MyBean myBean() {
        // 配置生效時(shí)創(chuàng)建 MyBean 實(shí)例
        return new MyBean();
    }
}

2.5 @ConditionalOnMissingBean

@ConditionalOnMissingBean 是一個(gè) Spring Boot 中常用的條件注解,它的作用是:當(dāng)容器中不存在指定的 Bean 時(shí),才會(huì)進(jìn)行配置。

定義了一個(gè)具有多個(gè)屬性的注解 ConditionalOnMissingBean,用于根據(jù)存在或缺少特定類型的 bean 來決定是否應(yīng)用某個(gè)配置。

示例和說明:

/**
 * 使用 @ConditionalOnMissingBean 注解來判斷容器中是否已經(jīng)存在了 MyService 類型的 Bean
 * 如果不存在,則創(chuàng)建一個(gè) MyServiceImpl 實(shí)例并返回
 * 否則,不進(jìn)行任何操作。
 */
@Configuration
public class MyConfiguration {
    @Bean
    @ConditionalOnMissingBean(MyService.class)
    public MyService myService() {
        return new MyServiceImpl();
    }
}

三、條件裝配的實(shí)現(xiàn)原理

條件裝配的實(shí)現(xiàn)原理主要基于Spring的IoC容器和@Conditional注解。

在Spring的IoC容器中,BeanFactoryPostProcessor和BeanPostProcessor是兩個(gè)核心的接口,它們?cè)试S我們?cè)赽ean的創(chuàng)建和配置過程中添加額外的邏輯。(想要了解源碼,讀者可以查看我前面的博文)

條件裝配的實(shí)現(xiàn)原理

@Conditional注解:這個(gè)注解可以標(biāo)記在類、方法或注解上,用于指定在特定的條件滿足時(shí)才創(chuàng)建和配置bean。@Conditional注解需要一個(gè)Class類型的參數(shù),這個(gè)參數(shù)需要實(shí)現(xiàn)Condition接口。Condition接口:這是一個(gè)函數(shù)式接口,它定義了一個(gè)matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法。

  • 這個(gè)方法返回一個(gè)boolean值,表示條件是否滿足。如果返回true,則Spring容器會(huì)創(chuàng)建和配置相應(yīng)的bean;如果返回false,則不會(huì)創(chuàng)建和配置。
  • 兩個(gè)參數(shù)提供了關(guān)于Spring容器和當(dāng)前正在評(píng)估的bean的元數(shù)據(jù)信息。

自動(dòng)配置:在Spring Boot中,條件裝配被廣泛應(yīng)用于自動(dòng)配置。

  • Spring Boot會(huì)根據(jù)我們?cè)?code>pom.xml文件中引入的依賴,自動(dòng)配置相應(yīng)的bean。
  • 這是通過一系列的AutoConfiguration類實(shí)現(xiàn)的,這些類上通常會(huì)使用@ConditionalOnClass、@ConditionalOnMissingBean等注解來指定條件。

四、實(shí)際案例

假設(shè)正在開發(fā)一個(gè)在線商城的 Spring Boot 應(yīng)用程序,其中包含了用戶管理和訂單管理兩個(gè)模塊?,F(xiàn)在,希望在用戶注冊(cè)時(shí)發(fā)送一封歡迎郵件,但是如果用戶已經(jīng)在系統(tǒng)中存在,則不發(fā)送郵件。

ps:使用條件注解 @ConditionalOnMissingBean 來實(shí)現(xiàn)這一定制化功能。

創(chuàng)建一個(gè)郵件服務(wù)接口 EmailService 和實(shí)現(xiàn)類 WelcomeEmailService

/**
 * 郵件服務(wù)接口
 */
public interface EmailService {
    void sendWelcomeEmail(String email);
}
/**
 * 發(fā)送歡迎郵件
 */
@Service
public class EmailServiceImpl implements EmailService {
    @Override
    public void sendWelcomeEmail(String email) {
        // 發(fā)送歡迎郵件的邏輯
        System.out.println("Sending welcome email to: " + email);
    }
}

創(chuàng)建一個(gè)用戶服務(wù)類 UserService,在用戶注冊(cè)時(shí)調(diào)用郵件服務(wù)發(fā)送歡迎郵件。

public interface UserService {
    public void registerUser(String email);
}
/**
 * 在用戶注冊(cè)時(shí)檢查是否已經(jīng)存在該用戶,如果不存在則發(fā)送歡迎郵件
 */
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final EmailService emailService;
    @Autowired
    public UserServiceImpl(UserMapper userMapper, EmailService emailService) {
        this.userMapper = userMapper;
        this.emailService = emailService;
    }
    @Override
    public void registerUser(String email) {
        if(!userMapper.existsByEmail(email)) {
            userMapper.save(email);
            emailService.sendWelcomeEmail(email);
        }else {
            throw new IllegalArgumentException("Email already exists");
        }
    }
}

創(chuàng)建一個(gè) UserRepository實(shí)現(xiàn),它使用HashSet來模擬存儲(chǔ)用戶信息。

/**
 * 不想使用數(shù)據(jù)庫,直接使用HashSet來模擬存儲(chǔ)用戶信息的email
 * 使用一個(gè)HashSet來存儲(chǔ)注冊(cè)過的email,HashSet不允許存儲(chǔ)重復(fù)的元素
 * @author LEK
 */
@Repository
public class UserMapper {
    private final Set<String> registeredEmails = new HashSet<>();
    public boolean existsByEmail(String email) {
        return registeredEmails.contains(email);
    }
    public void save(String email) {
        if (Objects.nonNull(email) && !email.isEmpty()) {
            registeredEmails.add(email);
        }
    }
}

使用 @ConditionalOnMissingBean 注解來確保只有在容器中不存在 EmailService 的實(shí)現(xiàn)類時(shí)才會(huì)注入 WelcomeEmailService。這樣,如果用戶在系統(tǒng)中已經(jīng)存在,就不會(huì)發(fā)送歡迎郵件。

@Configuration
public class EmailConfig {
    /**
     * 郵件配置
     * */
    @Bean
    @ConditionalOnMissingBean(EmailService.class)
    public EmailServiceImpl email() {
        return new EmailServiceImpl();
    }
}

新建UserServiceImplTest測(cè)試類,由于是使用HashSet來模擬運(yùn)行,每次啟動(dòng)都是不存在的,然后手動(dòng)一下。

@SpringBootTest
public class UserServiceImplTest {
    @Autowired
    private UserService userService;
    @Test
    public void testRegisterExistingUser() {
        String existingEmail = "existing@example.com";
        userService.registerUser(existingEmail);
        // 注冊(cè)已存在的用戶,預(yù)期會(huì)拋出 IllegalArgumentException
        userService.registerUser(existingEmail);
    }
}

運(yùn)行效果。

到此這篇關(guān)于解密Spring Boot深入理解條件裝配與條件注解的文章就介紹到這了,更多相關(guān)Spring Boot條件裝配與條件注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論