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

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

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

一、條件裝配概述

1.1 條件裝配的基本原理

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

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

條件注解的基本原理

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

1.2 條件裝配的作用

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

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

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

二、常用注解

2.1 @ConditionalOnClass

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

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

示例和用法說明

/**
 * 只有當應(yīng)用程序的類路徑中存在 RedisTemplate 類時,RedisConfiguration 類中定義的 redisTemplate() 方法才會被注冊為 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 中的一個條件注解,它的作用是在容器中存在指定的 Bean 時,才會應(yīng)用相應(yīng)的配置或組件。如果指定的 Bean 不存在,則該配置或組件將被忽略。

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

示例和用法說明

基本用法

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

多個 Bean 的情況

/**
 * MyService 類被標記為 @ConditionalOnBean({MyBean.class, AnotherBean.class}),這意味著只有當容器中同時存在 MyBean 和 AnotherBean 類型的 Bean 時,MyService 才會被創(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 類被標記為 @ConditionalOnBean(name = {"myBean", "anotherBean"}),這意味著只有當容器中同時存在名稱為 "myBean" 和 "anotherBean" 的 Bean 時,MyService 才會被創(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)用某個配置。

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

示例和說明

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

2.4 @ConditionalOnExpression

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

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

示例和說明:

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

2.5 @ConditionalOnMissingBean

@ConditionalOnMissingBean 是一個 Spring Boot 中常用的條件注解,它的作用是:當容器中不存在指定的 Bean 時,才會進行配置。

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

示例和說明:

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

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

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

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

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

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

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

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

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

四、實際案例

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

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

創(chuàng)建一個郵件服務(wù)接口 EmailService 和實現(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)建一個用戶服務(wù)類 UserService,在用戶注冊時調(diào)用郵件服務(wù)發(fā)送歡迎郵件。

public interface UserService {
    public void registerUser(String email);
}
/**
 * 在用戶注冊時檢查是否已經(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)建一個 UserRepository實現(xiàn),它使用HashSet來模擬存儲用戶信息。

/**
 * 不想使用數(shù)據(jù)庫,直接使用HashSet來模擬存儲用戶信息的email
 * 使用一個HashSet來存儲注冊過的email,HashSet不允許存儲重復(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 的實現(xiàn)類時才會注入 WelcomeEmailService。這樣,如果用戶在系統(tǒng)中已經(jīng)存在,就不會發(fā)送歡迎郵件。

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

新建UserServiceImplTest測試類,由于是使用HashSet來模擬運行,每次啟動都是不存在的,然后手動一下。

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

運行效果。

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

相關(guān)文章

最新評論