我有一个带有一些独立bean X的项目,它在一堆服务中自动装配。服务彼此使用,最后用于单入口点(控制器)。现在有了新的要求:实现X的几个版本,并根据入口点的参数(枚举XType)决定使用哪个版本。如果不改变服务就可以做到这一点。
我对解决方案的想法是创建自定义范围UsesX并实现<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:config="http://www.hp.com/maas/1.0.0/UpgraderConfig" targetNamespace="http://www.hp.com/maas/1.0.0/UpgraderConfig" elementFormDefault="qualified" version="1.0.0">
<xs:simpleType name="stringWithoutWhiteSpace">
<xs:annotation>
<xs:documentation>One or more occurrences of any character which is not whitespace (i.e. not space, tab, newline, return)</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:pattern value="\S+"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="UpgraderConfigContainer">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="Upgrader" type="config:UpgraderConfig"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="UpgraderConfig">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="className" type="config:stringWithoutWhiteSpace"/>
</xs:sequence>
</xs:complexType>
<xs:element name="UpgraderConfigs" type="config:UpgraderConfigContainer">
<xs:unique name="uniqueUpgraderName">
<xs:selector xpath="config:Upgrader"/>
<xs:field xpath="config:name"/>
</xs:unique>
</xs:element>
</xs:schema>
,它将使用UsesX将每个BeanFactoryPostProcessor
转换为每个XType的单例集。此外,它还会为此bean添加限定符,以便在控制器中为X和基于参数的选择创建工厂方法。但是如何在不改变类的情况下隐式地将这个限定符添加到服务中的BeanDefinition
?
UPD
好的,例如,我想在@Autowired
请求时使用db url "jdbc:mysql://Adb"
,在A
时使用"jdbc:mysql://Bdb"
:
B
此外,还需要在XML配置中配置enum DatabaseType {A, B}
@Controller
@RequestMapping(/)
class MyController {
@Autowired ServiceProvider provider; // some way to get service by DatabaseType
void foo(@RequestParam DatabaseType dbType) {
ServiceA a = provider.getA(dbType);
a.bar();
ServiceB b = provider.getB(dbType);
b.baz();
}
}
@Service
class ServiceA {
// Don't want to get information about different databases in services
@Autowired ServiceB b;
@Autowired ServiceC c;
@Autowired DaoFoo dao;
//...
}
@Service
class ServiceB {
@Autowired ServiceC c;
@Autowired DaoFoo daoFoo;
@Autowired DaoBar daoBar;
//...
}
@Service
class ServiceC {
@Autowired DaoBar daoBar;
//...
}
@Repository
class DaoFoo {
DaoFoo(String dbURL) {/*...*/}
}
@Repository
class DaoBar {
DaoFoo(String dbURL) {/*...*/}
}
和"jdbc:mysql://Adb"
。
答案 0 :(得分:3)
我想结束你的要求,以便我能说明你是否正确。
@Service
。X
类型的一种实现。X
实现的选择将由XType
枚举定义,而{1}}枚举可以从请求中获得。X
类型bean可以从xml
配置。 OP:如果其中一项服务被称为w / o X
,应该使用哪种XType
实施?
因此,如果我的理解是正确的,那么Proxy
类型似乎需要X
。
在此Proxy
中,您需要隐式地获取此XType
(f.ex.到ThreadLocal
var)。
使用@Autowired
时,bean首先按类型标识。因此,您需要使用现有的X
实现进行代理,并将当前实现和新实现提取到不同类型。
因此,您可能最终得到以下内容:
interface newX {
void save();
}
@Repository
class DaoFoo implements newX {
public void save() {...};
}
@Repository
class DaoBar implements newX {
public void save() {...};
}
class XImpl implements X, newX {
public final ThreadLocal<XType> currentXType = new ThreadLo...;
Map<XType, newX> mapping = ....
public void save() {mapping.get(currentXType.get()).save();};
}
答案 1 :(得分:1)
您的示例有点混乱,因为您的Service
被命名为A和B,但您也使用A和B作为DatabaseType
。但我想我明白你想要什么。
我认为您无法使用Autowired
执行此操作,但您可以将Service
设为@Scope("prototype")
并从上下文中检索它们。上下文应该在您第一次请求时实例化Service
,然后在提供相同的输入时重用相同的bean。
@Configuration
public class ServiceProvider{
...
@Bean
@Scope("prototype")
public ServiceA serviceA(DatabaseType dbType) {
...
}
@Bean
@Scope("prototype")
public ServiceB serviceB(DatabaseType dbType) {
...
}
}
@Controller
@RequestMapping(/)
class MyController {
@Autowired
ConfigurableApplicationContext context
void foo(@RequestParam DatabaseType dbType) {
AutowireCapableBeanFactory beanFactory = context.getBeanFactory();
ServiceA serviceA = (ServiceA)context.getBean("serviceA", dbType);
...
}
}
答案 2 :(得分:1)
创建一个服务界面,如:
interface ServiceInterface{
public boolean isTheOne(String type); // or some suitable name.
}
然后您的所有服务都需要实现此接口,然后在控制器
中 @Controller
@RequestMapping(/)
class MyController {
@Autowired
Set<ServiceInterface> provider;
void foo(@RequestParam DatabaseType dbType) {
ServiceInterface service = provider.stream().filter(s -> s.isTheOne(String dbType));
service.bar();
}
}
答案 3 :(得分:0)
您可以通过开发Qualifier
将XType保持为自定义@Interface
内的枚举器。
请在下面找到一个示例,该示例提到了基于不同类型数据类型的bean的条件接线:
@Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public static @interface DBHost{
public static enum DatabaseType {
A,
B
}
}
@Autowired
@DBHost(DBHost.DatabaseType.A)
ServiceBean serviceInstanceA;
查找限定符注释here
的其他用法