动态定义在 Spring 中自动装配哪个 bean(使用限定符)

2023-11-26

我有一个 Java EE + Spring 应用程序,它更喜欢注释而不是 XML 配置。 bean 始终具有原型范围。

现在,我的应用程序中的业务规则取决于用户请求所在的国家/地区。所以我会有这样的东西(请记住这个例子被大大简化了):

@Component
public class TransactionService {
    @Autowired
    private TransactionRules rules;
    //..
}


@Component
@Qualifier("US")
public class TransactionRulesForUS implements TransactionRules {
     //..
}

@Component
@Qualifier("CANADA")
public class TransactionRulesForCanada implements TransactionRules {
     //..
}

我正在寻找一种方法,使自动装配机制根据当前请求的国家/地区自动注入正确的 bean(在本例中是美国或加拿大)。该国家/地区将存储在 ThreadLocal 变量中,并且会在每个请求中发生变化。对于所有没有自己特定规则的国家来说,还会有一个全球类别。

我想我必须自定义 Spring 决定如何创建它将注入的对象的方式。我发现做到这一点的唯一方法是使用 FactoryBean,但这并不完全是我所希望的(不够通用)。我希望做这样的事情:

  1. 在 Spring 实例化对象之前,必须调用我自己的自定义代码。
  2. 如果我检测到所请求的接口有多个实现,我会在 ThreadLocal 变量中查找正确的国家/地区,并动态地将适当的限定符添加到自动连接请求中。
  3. 之后,Spring 将发挥其所有通常的魔力。如果添加限定符,则必须考虑这一点;如果没有,流程将照常进行。

我走的路正确吗?我对此有什么想法吗?

Thanks.


创建您自己的注释,用于装饰实例变量或 setter 方法,然后是处理注释并注入通用代理的后处理器,该代理在运行时解析正确的实现并将调用委托给它。

@Component
public class TransactionService {
  @LocalizedResource
  private TransactionRules rules;
  //..
}

@Retention(RUNTIME)
@Target({FIELD, METHOD})
public @interface LocalizedResource {}

这是算法postProcessBeforeInitialization(bean, beanName)bean 后处理器中的方法:

  1. 内省 bean 类以查找使用 @LocalizedResource 注释的实例变量或 setter 方法。将结果存储在按类名索引的缓存(只是一个映射)中。你可以使用 Spring 的InjectionMetadata以此目的。您可以通过在 Spring 代码中搜索此类的引用来查找有关其工作原理的示例。
  2. 如果 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为此目的,为了添加新的BeanDefinitions 到注册表,并带有适当的限定符,每个区域设置感知接口的实现都有一个限定符。您可以通过以下命名约定来猜测实现的区域设置:如果区域设置感知接口称为 TransactionRules,则实现可能在同一包中命名为 TransactionRules_ISOCODE。

如果您无法承担这样的命名约定,则需要某种类路径扫描+一种猜测给定实现的语言环境的方法(可能是实现类上的注释)。类路径扫描是可能的,但相当复杂且缓慢,因此请尽量避免它。

以下是所发生情况的摘要:

  1. 当应用程序启动时,将发现 TransactionRules 的实现,并为每个实现创建 bean 定义,并使用与每个实现的区域设置相对应的限定符。这些 bean 的 bean 名称不相关,因为查找是根据类型和限定符执行的。
  2. 在执行期间,在线程局部变量中设置当前区域设置
  3. 查找您需要的 bean(例如 TransactionService)。后处理器将为每个 @LocalizedResource 实例字段或 setter 方法注入一个代理。
  4. 当调用 TransactionService 上的方法并最终进入某些 TransactionRules 的方法时,绑定到代理的调用处理程序会根据存储在线程局部变量中的值切换到正确的实现,然后将调用委托给该实现。

这并不是微不足道的,但它确实有效。这实际上是 Spring 处理 @PersistenceContext 的方式,除了实现查找之外,这是用例的附加功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态定义在 Spring 中自动装配哪个 bean(使用限定符) 的相关文章

  • 如何使用 Maven Failsafe 插件运行 JUnit 5 集成测试?

    当我运行命令时 Maven Failsafe 插件找不到我的 JUnit 5 集成测试mvn clean failsafe integration test 尽管它可以找到文件 我有junit jupiter api and junit j
  • Quarkus 不以编程方式选择 bean

    我试图以编程方式选择 bean 但 quarkus 不会注入 bean 并引发异常 不支持吗 public enum ReportType ONE TWO Qualifier Retention RUNTIME Target METHOD
  • 如何配置 Spring-WS 以使用 JAXB Marshaller?

    感谢您到目前为止对此的帮助 我正在更新问题 因为我没有显示我需要的所有内容 并显示了建议的更改 肥皂输出仍然不是我想要的 servlet xml
  • 在命令行java中突出显示文本[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一项任务是重新创建 unix cal 程序 除了一部分之外 相当简单 今天 它突出显示了该数字 我不知道该怎么做 关于如何在 Ja
  • java中的单链表和双向链表?

    在java中 哪个集合接口可以有效地实现单链表和双向链表 请问代码示例吗 毫不奇怪 实现双向链表的正确接口是 LinkedList 看Java文档 http docs oracle com javase 8 docs api java ut
  • 需要正则表达式帮助

    我正在尝试替换两次或多次出现的 br like br br br 标签与两个一起 br br 具有以下模式 Pattern brTagPattern Pattern compile lt s br s s gt s 2 Pattern CA
  • 在 Junit 测试中使用 ReflectionTestUtils.setField()

    我是 JUnittesting 的新手 所以我有一个问题 谁能告诉我为什么我们使用ReflectionTestUtils setField 在我们的 Junit 测试示例中 正如评论中提到的 java 文档很好地解释了用法 但我还想给你们举
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • Android volley使用RequestFuture.get()时出现超时异常

    在我的片段中 我尝试使用 TMDB 的开放电影数据库来获取有关 正在播放 电影的详细信息 如果我使用 RequestFuture get time TimeUnit 方法来执行此齐射请求 我总是会收到超时错误 如果我在 Safari 中手动
  • 从 HttpClient 3 转换为 4

    我已经成功地对所有内容进行了更改 但以下内容除外 HttpClient client HttpPost method client new DefaultHttpClient method new HttpPost url InputStr
  • 如何配置Spring boot分页从第1页开始,而不是从0开始

    boot 1 4 0 可分页 用于分页 它工作正常 没有任何问题 但默认情况下 页面值从 0 开始 但在前端 页面值从 1 开始 那么是否有任何标准方法来增加值而不是手动增加代码内的页码 public Page
  • Cucumber DataTable 错误 - io.cucumber.datatable.UndefinedDataTableTypeException:无法将 DataTable 转换为 cucumber.api.DataTable

    尝试使用 cucumber selenium java intelliJ 运行场景 但在其中一个步骤中出现有关 DataTable 的错误 在我开始使用测试运行程序并更改周围的一些内容之前 数据表工作正常并正确转换该步骤的参数 但我就是无法
  • 在循环中按名称访问变量

    我正在开发一个 Android 项目 并且有很多可绘制对象 这些绘图的名称都类似于icon 0 png icon 1 png icon 100 png 我想将这些可绘制对象的所有资源 ID 添加到整数 ArrayList 中 对于那些不了解
  • Java和手动执行finalize

    如果我打电话finalize 在我的程序代码中的一个对象上 JVM当垃圾收集器处理这个对象时仍然再次运行该方法吗 这是一个大概的例子 MyObject m new MyObject m finalize m null System gc 是
  • 在 Freemarker 模板中检查 Spring 安全角色和记录的用户名

    有谁知道 freemarker 标签来检查 freemarker 文件中的 spring 安全角色和用户名 我从网络上的几个资源中发现以下代码将打印登录的用户名 但它没有打印用户名 而是打印 登录为
  • Java 中的微分方程

    我正在尝试用java创建一个简单的SIR流行病模型模拟程序 基本上 SIR 由三个微分方程组定义 S t l t S t I t l t S t g t I t R t g t I t S 易感人群 I 感染人群 R 康复人群 l t c
  • 使用自定义比较器在 Java 中创建 SortedMap

    我想创建一个TreeMap在 Java 中具有自定义排序顺序 排序后的键是字符串 需要根据第二个字符进行排序 这些值也是字符串 示例地图 Za FOO Ab Bar 您可以像这样使用自定义比较器 Comparator
  • @Embeddable 中的 @GenerateValue

    我已将实体的 id 分离到一个单独的 Embeddable 类中 该实体如下 Entity Table name users public class Users EmbeddedId private Users pk id private
  • 你能快速告诉我这个伪代码是否有意义吗?

    我相信我的代码现在是万无一失的 我现在将写出伪代码 但我确实有一个问题 为什么 DRJava 要求我返回 if 语句之外的内容 正如你所看到的 我为 ex 写了 return 1 只是因为它问了 但是它永远不会返回该值 谁可以给我解释一下这
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时

随机推荐