【Spring Boot】4.條件化Bean 根據配置文件加載對應Bean

根據配置文件只加載指定的Bean,條件化Bean

近期在工作中遇到實際問題:在不同的環境中,需要加載不同的工具類。這個就可以使用到Spring的條件化Bean。

話不多說,直接上代碼。
例如,當前對於IService接口:

public interface IService {
    void test();
}

有兩個不同的實現類:

public class AwsServiceImpl implements IService{
    @Override
    public void test() {
        System.out.println("AwsServiceImpl test ... ");
    }
}
public class HttpServiceImpl implements IService{
    @Override
    public void test() {
        System.out.println("HttpServiceImpl test ... ");
    }
}

而在不同的環境中,需要調用不同的實現類。一種思路是在配置文件中聲明環境,並將兩個實現類存入一個map<String, IService>中,KEY爲不同的環境,即在不同的環境中,可以調用特定的實現類,具體的代碼如下:
首先在配置文件中聲明環境:

# 使用 aws,internal 標明外網環境與內網環境
env=aws

代碼實現:

@Service
public class TestService {

    private final static String ENV_AWS = "aws";
    private final static String ENV_INTERNAL = "internal";

    private String env;
    private AwsServiceImpl awsService;
    private HttpServiceImpl httpService;
    private Map<String, IService> serviceMap;

    @Autowired
    public TestService(AwsServiceImpl awsService, HttpServiceImpl httpService, @Value("${env}") String env) {
        this.awsService = awsService;
        this.httpService = httpService;
        this.env = env;
    }

    @PostConstruct
    public void init() {
        // 初始化 Map<String, IService>
        serviceMap = new HashMap<>(4);
        serviceMap.put(ENV_AWS, awsService);
        serviceMap.put(ENV_INTERNAL, httpService);
    }

    public void test() {
        // 根據環境配置,調用不同的服務
        serviceMap.get(env).test();
    }
}

該思路可以實現功能,但缺點在於多初始化了一個不會使用到的類,同時每次調用服務時,還需要獲取特定的服務。因此,我們希望,能根據配置文件,只加載特定的Bean。這裏就要使用到ConditionalOnProperty註解。
通過配置:

@ConditionalOnProperty(
        name = "xx",
        havingValue = "yy"
)

Spring會判斷配置文件中的配置項xx,是否值爲yy,如果值不相等,則不會生成該類,現在將上面的代碼進行修改。
兩個實現類:

@Service
@ConditionalOnProperty(
        name = "env",
        havingValue = "aws"
)
public class AwsServiceImpl implements IService{

    @PostConstruct
    public void init() {
        System.out.println("AwsServiceImpl init ... ");
    }

    @Override
    public void test() {
        System.out.println("AwsServiceImpl test ... ");
    }
}

@Service
@ConditionalOnProperty(
        name = "env",
        havingValue = "internal"
)
public class HttpServiceImpl implements IService{

    @PostConstruct
    public void init() {
        System.out.println("HttpServiceImpl init ... ");
    }

    @Override
    public void test() {
        System.out.println("HttpServiceImpl test ... ");
    }
}

此時配置文件配置:

env=aws

啓動項目,查看日誌,可以發現與配置值對應的AwsServiceImpl進行了初始化:
在這裏插入圖片描述而在其他類中,若要調用,也無需再採用Map的形式,可以直接注入對應類。雖然有兩個接口的實現類,但是由於實際程序運行時,只有一個實現類會被初始化,因此下面的代碼可以正確調用。

@Service
public class MainService {

    private IService iService;

    @Autowired
    public MainService(IService iService) {
        this.iService = iService;
    }
    
    public void test() {
        iService.test();
    }
}

博客代碼的Github鏈接:https://github.com/Parallelline1996/Spring-Boot-Learning/tree/master/code-repository/SpringBoot-Conditional-Property

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