Spring入門(六):條件化的bean


1. 概念

默認情況下,Spring中定義的bean在應用程序啟動時會全部裝配,不管當前運行的是哪個環境(Dev,QA或者Prod),也不管當前運行的是什么系統(Windows或者Linux),但有些使用場景下,我們可能需要條件化的裝配某些bean,即當滿足某一條件時,裝配某些bean,當不滿足某一條件時,就忽略掉某些bean。

這個條件可以很簡單,比如當某個jar包存在時,當存在某個環境變量時,也可以很復雜。

針對這個使用場景,Spring中提供了@Conditional注解來實現條件化的bean。

2. 示例

為了更好的理解,我們通過具體的代碼示例來理解下條件化的bean的實現方式。

由於Windows系統和Linux系統顯示列表的命令不同,Windows下是dir,Linux下是ls,因此我們的需求是,應用程序啟動時自動根據當前系統裝配需要的bean,比如我的電腦系統是Windows 7,那就只裝配Windows系統所需要的bean。

首先,定義一個接口ListService,該接口只包含一個方法showListCmd:

package chapter03.conditional;

public interface ListService {
    String showListCmd();
}

然后定義該接口的2個實現類WindowsListService和LinuxListService:

package chapter03.conditional;

public class WindowsListService implements ListService {
    public WindowsListService() {
        System.out.println("This is WindowsListService constructor");
    }
    
    @Override
    public String showListCmd() {
        return "dir";
    }
}
package chapter03.conditional;

public class LinuxListService implements ListService {
    public LinuxListService() {
        System.out.println("This is LinuxListService constructor");
    }
    
    @Override
    public String showListCmd() {
        return "ls";
    }
}

然后分別定義Windows系統和Linux系統的判斷條件:

package chapter03.conditional;

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 conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return conditionContext.getEnvironment().getProperty("os.name").contains("Windows");
    }
}
package chapter03.conditional;

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 conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return conditionContext.getEnvironment().getProperty("os.name").contains("Linux");
    }
}

值得注意的是,這2個類都需要實現Condition接口,並重寫方法matches(),如果該方法返回true時,使用該條件的1個或多個bean就會被裝配,如果該方法返回false,使用該條件的1個或多個bean就會被忽略。

然后,定義Java配置類ConditionalConfig:

package chapter03.conditional;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConditionalConfig {
    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windowsListService() {
        return new WindowsListService();
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() {
        return new LinuxListService();
    }
}

這里聲明bean時除了使用@Bean注解,還使用了@Conditional注解,這個注解是實現條件化的bean的關鍵,它的參數可以傳遞任何實現了Condition接口並重寫了matches()方法的類,這里傳遞的是我們上面定義的WindowsCondition和LinuxCondition。

最后,我們定義一個Main類,在其main()方法中添加如下測試代碼:

package chapter03.conditional;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionalConfig.class);

        ListService listService = context.getBean(ListService.class);

        System.out.println(context.getEnvironment().getProperty("os.name") + "系統下的列表命令為:" + listService.showListCmd());

        context.close();
    }
}

運行結果如下所示:

This is WindowsListService constructor

Windows 7系統下的列表命令為:dir

從運行日志可以看出,由於當前系統是Windows 7,我們聲明的linuxListService bean並沒有被裝配。

3. 源碼及參考

源碼地址:https://github.com/zwwhnly/spring-action.git,歡迎下載。

汪雲飛《Java EE開發的顛覆者:Spring Boot實戰》

Craig Walls 《Spring實戰(第4版)》

原創不易,如果覺得文章能學到東西的話,歡迎點個贊、評個論、關個注,這是我堅持寫作的最大動力。

如果有興趣,歡迎添加我的微信:zwwhnly,等你來聊技術、職場、工作等話題(PS:我是一名奮斗在上海的程序員)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM