[英]Spring Boot design for service with multiple providers(small services)
我正在創建一個Spring Boot應用程序,我在設計服務時需要幫助。 我將以自行車服務為例。 讓我們考慮以下端點:
/api/bike/v1/info
/api/bike/v1/find
端點將調用Bike服務,該服務可能會調用不同的提供程序,例如BikeProvider1,BikeProvider2等。提供程序將在應用程序的屬性中指定,這允許更改提供程序而無需重新啟動應用程序。
結構實例
+ bike
+ Client
- BikeRequest.java
- BikeResponse.java
+ domain
- Providers.java //providers enums
- ServiceType.java // service type enums
+ Exceptions
+ Controller
- BikeController.java
+ Service
+ Providers
- BikeProviderService.java //interface
- BikeProbider1ProviderService.java // implements interface
- BikeProbider2ProviderService.java // implements interface
- BikeService.java //interface
- BikeServiceImpl.java
Properties.file
bike.provider.primary: BikeProvider1
bike.provider.fallback: BikeProvider2
我還認為,將來我希望有2個提供商作為后備,以防第一個提供商沒有響應。 但是現在,我將僅使用主數據庫。
我當前的設計是這樣,我有用於服務類型和提供程序的枚舉類。 在BikeServiceImpl.java中,我動態找到所需的提供程序並進行調用。
*******************ENUM CLASSES **************************
public enum Provider {
BIKEPROVIDER1 ("BikeProvider1"),
BIKEPROVIDER2 ("BikeProbider2"),
private String name;
Provider(final String name) {
this.name = name;
}
}
public enum ServiceType {
BIKEINFORMATION ("BikeInformation"),
FINDBIKE ("FindBike");
private String type;
ServiceType(final String name) {
this.type = name;
}
}
*****************BikeProviderService interface**************************
// this is the interface that all providers will implement
public interface BikeProviderService {
Optional<Bike> getBikeInformation(BikeRequest bike);
Optional<Bike> findBike(BikeRequest bike);
}
*****************BikeServiceImpl**************************
public class BikeServiceImpl implements BikeService {
// I autowired providers
@Autowired
private BikeProvider1 bikeProvider1;
@Autowired
private BikeProvider2 bikeProvider2;
//Get the provider from the properties
@Value("${bike.provider.primary:}")
private String primaryProvider;
// This is the call from controller endpoint /api/bike/v1/info
@Override
public Bike findBikeInformation(BikeRequest bike, ServiceType serviceType) throws ServiceProviderException, BikeNotFoundException {
return executeBikeInformationWithProvider(primaryProvider, bike, serviceType);
}
private Bike executeBikeInformationWithProvider(String provider, BikeRequest bike, ServiceType serviceType) throws ServiceProviderException, BikeNotFoundException {
// find the providers based on the property value
Optional<BikeProviderService> bikeProviderService = providerImplementation(provider);
Optional<Bike> bikeResponse;
if (BikeProviderService.isPresent()) {
try {
bikeResponse = bikeProviderService.get().getBikeInformation(bike);
if (bikeResponse.isPresent()) {
LogCacheService.logRequest(bikeResponse, provider, serviceType.getType());
return bikeResponse.get();
}
} catch (Exception ex) {
throw new ServiceProviderException("message");
}
}
throw new BikeNotFoundException("Bike Not found");
}
// This is the call from controller endpoint /api/bike/v1/find
@Override
public Bike findBike(BikeRequest bike, ServiceType serviceType) throws ServiceProviderException, BikeNotFoundException {
return executeFindBikeWithProvider(primaryProvider, bike, serviceType) ;
}
private Bike executeFindBikeWithProvider(String provider, BikeRequest bike, ServiceType serviceType) throws ServiceProviderException, BikeNotFoundException {
// find the providers based on the property value
Optional<BikeProviderService> bikeProviderService = providerImplementation(provider);
Optional<Bike> bikeResponse;
if (bikeProviderService.isPresent()) {
try {
bikeResponse = bikeProviderService.get().findBike(bike);
if (bikeResponse.isPresent()) {
LogCacheService.logRequest(bike, provider, serviceType.getType());
return bikeResponse.get();
}
} catch (Exception ex) {
throw new ServiceProviderException("message");
}
}
throw new BikeNotFoundException("Bike Not found");
}
private Optional<BikeProviderService> providerImplementation(String bikeProvider) {
Provider provider = null;
try {
provider = Provider.valueOf(bikeProvider.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ex) {
log.error("Bike:: invalid Provider {}" , bikeProvider);
}
if (provider != null) {
switch (provider) {
case BIKEPROVIDER1:
return Optional.ofNullable(bikeProvider1);
case BIKEPROVIDER2:
return Optional.ofNullable(bikeProvider2);
default:
return Optional.empty();
}
}
return Optional.empty();
}
我非常努力地不重復代碼,但是我擔心我會使此代碼過於復雜並且難以維護。 立即添加新的提供程序:
1.- add to the enum provider class
2.- add to the switch statement
3.- add the service and @AutoWire the class
我嘗試了工廠模式,但是我不想每次都創建提供者的新實例。 並且接近於我擁有的providerImplementation
方法。
另外,我創建了執行/輔助方法,因為正如我前面提到的,我願做一回退或與恢復方法fallback.Provider
的未來。 示例如果findBike失敗,我可以調用帶有后備功能的executeFindBikeWithProvider。 executeFindBikeWithProvider(**fallbackProvider**, bike, serviceType)
謝謝,讓我知道您是否需要更多詳細信息。
這不是Spring @Profile的好用例嗎?
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
https://www.baeldung.com/spring-profiles
您可以使用其他配置文件來更改運行時配置,而不是使用屬性文件中的提供程序列表。 這將有效地使您根據個人資料設置忽略或啟用您的提供程序。
這樣,添加新的提供程序僅需要您實現新的提供程序並將其與配置文件相關聯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.