Spring 條件Bean配置實現

Spring 條件Bean配置實現

本文介紹Spring 4引入的一個新特性,條件實例化Bean。我們首先了解下Spring4之前的實現方式,接着學習Spring4 提供的Condition接口和 @Conditional註解。

1. 概述

有時需要根據環境創建依賴注入bean,環境可能是正在運行的操作系統、或應用服務器等。Bean配置也可能依賴具體哪個Java版本,環境變量的屬性值,或你的應用正運行的階段,如開發、測試、生產階段等。諸如此類情況,我們需要根據條件實例化bean。

2. Spring 3 實現

2.1. Spring Expression Language (SpEL)實現

Spring3 提供了Spring Expression Language (SpEL),利用SpEl可以實現根據條件裝載Bean。下面通過示例進行說明:

public class MyDao {
  @Value("#{systemProperties['os.arch'].equals('x86') ? winDataSource : unixDataSource}")
  private DataSource datasource;
  ...
}

這裏在@Value註解中通過SpEl表達式進行條件加載。

2.2. Profile實現

Spring 3.1 提供了基於Profile的bean配置/創建。即能夠使用配置類基於一定命名環境創建bean。

爲了演示該特性,假設我們應用根據不同環境需要不同的bean配置,如郵件服務Bean依賴不同的操作系統,示例代碼如下:

@Configuration
public class MyConfiguration {
 
  @Bean
  public EmailService emailerService(){
    if (System.getProperty("os.name").contains("Windows")){
      return new WindowsEmailService();
    }
    return new LinuxEmailService();
  }
}

@Bean註解的方法動態返回正確的郵件服務bean。

從Spring 3.1開始,這種硬編碼方法的另一種替代方法(如果需要支持其他操作系統會發生什麼?)是使用Profile實現。通過@Profile定義一組bean。我們例子需要兩個profile,分別對應Windows和Linux。

@Configuration
@Profile("Linux")
public class LinuxConfiguration {
 
  @Bean
  public EmailService emailerService() {
    return new LinuxEmailService();
  }
}
@Profile("Windows") 
public class WindowsConfiguration {
 
  @Bean
  public EmailService emailerService() {
    return new WindowsEmailService();
  }
}

profile準備就緒後,可以通過setActiveProfiles()選擇合適的bean:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("Linux");
context.scan("com.intertech");
context.refresh();

3. Spring 4 實現方式

Spring 4 增加了新的 @Conditional 註解可以實現類似條件配置,但不在需要profile。還是用上面的示例進行說明。需要兩個類分別實現Condition接口,並實現matches()方法,在方法類檢查條件返回boolean值表明是否條件符合。

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
 
public class LinuxCondition implements Condition{
 
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    return context.getEnvironment().getProperty("os.name").contains("Linux");  }
}
import org.springframework.context.annotation.Condition; 
import org.springframework.context.annotation.ConditionContext; 
import org.springframework.core.type.AnnotatedTypeMetadata; 
 
public class WindowsCondition implements Condition{
 
  @Override 
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    return context.getEnvironment().getProperty("os.name").contains("Windows");
  }
}

ConditionContext參數給matches方法提供了訪問環境、容器、類加載器等能力,可以利用這些決定返回是否符合條件。AnnotatedTypeMetadata參數給matches提供訪問增加條件註解的方法。

條件設置好了,現在定義配置類,給創建bean的方法增加條件註解@Conditional,並指定對於的條件類。

import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class MyConfiguration {
 
  @Bean(name="emailerService")
  @Conditional(WindowsCondition.class)
  public EmailService windowsEmailerService(){
      return new WindowsEmailService();
  }
 
  @Bean(name="emailerService")
  @Conditional(LinuxCondition.class)
  public EmailService linuxEmailerService(){
    return new LinuxEmailService();
  }
}

雖然兩個bean都命名爲“emailerService”,但只有其中一個被容器調用基於條件創建bean。

該示例僅使用創建bean的條件。實際上這些條件可以作爲可重用的機制,用於對各種bean進行條件設置。

4. 總結

本文帶你瞭解Spring不同版本實現條件化實現Bean機制。條件Bean是Spring Boot簡化配置的底層實現機制,希望本文能夠加深你對Spring的理解和青睞。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章