根據配置文件只加載指定的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