1.介绍
介绍如何在 Spring 中动态地自动装配 bean。
首先展示一个动态自动装配可能会有所帮助的真实用例。 除此之外,将展示如何在 Spring 中以两种不同的方式解决它。
2.动态自动装配用例
动态自动装配在需要动态更改 Spring 的 bean 执行逻辑的地方很有帮助。 这在根据一些运行时变量选择要执行的代码的地方尤其实用。
为了演示一个真实的用例,创建一个控制世界不同地区的服务器的应用程序。 出于这个原因,创建了一个带有两个简单方法的接口:
public interface RegionService {
boolean isServerActive(int serverId);
String getISOCountryCode();
}
两个实现类
@Service("GBregionService")
public class GBRegionService implements RegionService {
@Override
public boolean isServerActive(int serverId) {
return false;
}
@Override
public String getISOCountryCode() {
return "GB";
}
}
@Service("USregionService")
public class USRegionService implements RegionService {
@Override
public boolean isServerActive(int serverId) {
return true;
}
@Override
public String getISOCountryCode() {
return "US";
}
}
假设有一个网站,用户可以选择检查服务器是否在所选区域中处于活动状态。 因此,希望有一个服务类,在给定用户输入的情况下动态更改 RegionService 接口实现。 毫无疑问,这是动态 bean 自动装配发挥作用的用例。
3.使用BeanFactory
BeanFactory 是用于访问 Spring bean 容器的根接口。 特别是,它包含获取特定 bean 的有用方法。 由于 BeanFactory 也是一个 Spring bean,可以自动装配并直接在类中使用它:
@Service
public class BeanFactoryDynamicAutowireService {
/**
* 服务名后缀
*/
private static final String SERVICE_NAME_SUFFIX = "regionService";
private final BeanFactory beanFactory;
@Autowired
public BeanFactoryDynamicAutowireService(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public boolean isServerActive(String isoCountryCode, int serverId) {
RegionService service = beanFactory.getBean(getRegionServiceBeanName(isoCountryCode),
RegionService.class);
return service.isServerActive(serverId);
}
private String getRegionServiceBeanName(String isoCountryCode) {
return isoCountryCode + SERVICE_NAME_SUFFIX;
}
}
使用了 getBean() 方法的重载版本来获取具有给定名称和所需类型的 bean。
虽然这可行,但真的更愿意依赖更惯用的东西; 也就是说,使用依赖注入的东西。
4.使用接口
为了通过依赖注入解决这个问题,将依赖 Spring 鲜为人知的特性之一。
除了标准的单字段自动装配之外,Spring 还能够把特定接口实现的所有 bean 收集到 Map 中:
@Service
public class CustomMapFromListDynamicAutowireService {
private final Map<String, RegionService> servicesByCountryCode;
@Autowired
public CustomMapFromListDynamicAutowireService(List<RegionService> regionServices) {
servicesByCountryCode = regionServices.stream()
.collect(Collectors.toMap(RegionService::getISOCountryCode, Function.identity()));
}
public boolean isServerActive(String isoCountryCode, int serverId) {
RegionService service = servicesByCountryCode.get(isoCountryCode);
return service.isServerActive(serverId);
}
}
在构造函数中创建了一个map,该map按国家代码保存实现。 此外,可以稍后在方法中使用它来获取特定实现,以检查给定服务器是否在特定区域中处于活动状态。