创建您自己的注释,用于装饰实例变量或 setter 方法,然后是处理注释并注入通用代理的后处理器,该代理在运行时解析正确的实现并将调用委托给它。
@Component
public class TransactionService {
@LocalizedResource
private TransactionRules rules;
//..
}
@Retention(RUNTIME)
@Target({FIELD, METHOD})
public @interface LocalizedResource {}
这是算法postProcessBeforeInitialization(bean, beanName)
bean 后处理器中的方法:
- 内省 bean 类以查找使用 @LocalizedResource 注释的实例变量或 setter 方法。将结果存储在按类名索引的缓存(只是一个映射)中。你可以使用 Spring 的
InjectionMetadata
以此目的。您可以通过在 Spring 代码中搜索此类的引用来查找有关其工作原理的示例。
- 如果 bean 存在这样的字段或方法,请使用下面描述的 InvocableHandler 创建一个代理,并将当前的 BeanFactory 传递给它(bean 后处理器必须是 ApplicationContextAware)。将该代理注入实例变量,或使用代理实例调用 setter 方法。
这是将用于创建本地化资源的代理的 InitationHandler。
public class LocalizedResourceResolver implements InvocationHandler {
private final BeanFactory bf;
public LocalizedResourceResolver(BeanFactory bf) {
this.bf = bf;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String locale = lookupCurrentLocale();
Object target = lookupTarget(locale);
return method.invoke(target, args);
}
private String lookupCurrentLocale() {
// here comes your stuff to look up the current locale
// probably set in a thread-local variable
}
private Object lookupTarget(String locale) {
// use the locale to match a qualifier attached to a bean that you lookup using the BeanFactory.
// That bean is the target
}
}
您可能需要对 bean 类型进行更多控制,或者在 InvocableHandler 中添加请求的 bean 类型。
接下来的事情是自动检测给定接口的实现(这些接口是本地相关的),并使用与区域设置相对应的限定符来注册它们。您可以实施一个BeanDefinitionRegistryPostProcessor
or BeanFactoryPostProcessor
为此目的,为了添加新的BeanDefinition
s 到注册表,并带有适当的限定符,每个区域设置感知接口的实现都有一个限定符。您可以通过以下命名约定来猜测实现的区域设置:如果区域设置感知接口称为 TransactionRules,则实现可能在同一包中命名为 TransactionRules_ISOCODE。
如果您无法承担这样的命名约定,则需要某种类路径扫描+一种猜测给定实现的语言环境的方法(可能是实现类上的注释)。类路径扫描是可能的,但相当复杂且缓慢,因此请尽量避免它。
以下是所发生情况的摘要:
- 当应用程序启动时,将发现 TransactionRules 的实现,并为每个实现创建 bean 定义,并使用与每个实现的区域设置相对应的限定符。这些 bean 的 bean 名称不相关,因为查找是根据类型和限定符执行的。
- 在执行期间,在线程局部变量中设置当前区域设置
- 查找您需要的 bean(例如 TransactionService)。后处理器将为每个 @LocalizedResource 实例字段或 setter 方法注入一个代理。
- 当调用 TransactionService 上的方法并最终进入某些 TransactionRules 的方法时,绑定到代理的调用处理程序会根据存储在线程局部变量中的值切换到正确的实现,然后将调用委托给该实现。
这并不是微不足道的,但它确实有效。这实际上是 Spring 处理 @PersistenceContext 的方式,除了实现查找之外,这是用例的附加功能。