问题描述
@Service
public class Animal {
public String name;
}
@Service
public class Dog extends Animal {
public String name;
}
@Service
public class Cat extends Animal {
public String name;
}
在spring boot项目中,我想使用spring框架提供的ApplicationContext获得一个特定的bean,这是我写来说明的一个简单示例:
@Component
public class AnimalLocator implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (PayServiceLocator.applicationContext == null) {
PayServiceLocator.applicationContext = applicationContext;
}
}
public <T extends Animal> T getService(String name) {
if("Cat".equals(name) {
applicationContext.getBean(name, Cat.class);
}
if("Dog".equals(name) {
applicationContext.getBean(name, Dog.class);
}
}
}
但是,编译器提示了异常:
马赛克部分应该是狗或猫。 我认为它应该起作用,因为T已经扩展了Animal类,但是它没有,那么有人对此有任何想法吗? 谢谢!
1楼
由于您正在使用bean类访问bean实例,因此直接将class作为参数传递是很简单的:
public <T extends Animal> T getPayService(String name, Class<T> payClass) {
return applicationContext.getBean(name, payClass);
}
2楼
当然, getPayService
T
将扩展Animal
。
这意味着用另一种类型调用它的代码将无法编译:
Fruit fruit = animalLocator.getPayService("Banana")
为了说明您当前的问题 ,请查看以下内容:
Cat cat = animalLocator.getPayService("Dog");
在这种情况下, T
是Cat
,但是您的代码将返回Dog
。
为了避免编译器错误,可以添加类型强制转换:
return (T) applicationContext.getBean(...
但这仍然是不安全的,因为编译器仍然无法保证实际的返回类型将是运行时调用方上下文中T
值,并且调用方将具有类强制转换异常。
如果我们可以假设getBean
是一个安全的调用,那么您应该将方法更改为以下实现:
public <T extends Animal> T getPayService(String name, Class<T> cls) {
return applicationContext.getBean(name, cls);
}
从调用者的角度来看,这并没有太大变化,而是取决于applicationContext.getBean(name, cls);
的事实(或假设applicationContext.getBean(name, cls);
将返回类型T
的对象。
这意味着您的代码与getBean
一样具有类型安全性,但是编译器对此感到满意。
3楼
您可以将所有Animal实例自动绑定到Map中,而无需编写if / else:
@Service("Animal")
public class Animal {
public String name;
}
@Service("Dog")
public class Dog extends Animal {
}
@Service("Cat")
public class Cat extends Animal {
}
在您的AnimalLocator中:
@Component
public class AnimalLocator {
@Autowired
private Map<String,Animal> animals;
public <T extends Animal> T getService(String name) {
return this.animals.get(name);
}
}