【问题标题】:Spring @Configuration @Bean - How can I get more context information for bean creation?Spring @Configuration @Bean - 如何获取更多用于创建 bean 的上下文信息?
【发布时间】:2016-01-25 12:10:11
【问题描述】:

我想创建一个基于“该字段属于哪个类的实例(甚至,只是该字段属于哪个类)的 bean。类似于:

@Configuration
@ComponentScan
public class MyConfiguration {
    @Bean
    SomeClass getTheRightInstance(SomeContext someContext) {
        if(someContext.getinjectedFieldHostInstance.getId() == 7) {
            return new SpecificSomeClassImplForId7();
        } else {
            return new SomeClass();
        }
    }

Bean 将被注入到以下field

public class A {
   private int final id;
   @Inject private SomeClass field;
   int getId();
   public A() {
     id = SerialIdGenerator.getNextID();
   }
}

根据A实例的id选择注入Afield的bean

public staitc void main(String[] args) {
    A a1 = new A();  // has id '1', gets field injected with SimpleClass 
    A a2 = new A();  // has id '2', gets field injected with SimpleClass
    ...
    A a7 = new A();  // gets field injected with SpecificSomeClassImplForId7
    ...
    A last= new A();  // has id!=7, gets field injected with SimpleClass

}

一般的想法是决定在代码中定义哪个实现注入哪个类中的哪个字段。

我可以将不同的 bean 实例注入到同一类的不同实例的同一字段中吗?怎么通过代码来配置呢?

【问题讨论】:

    标签: java spring dependency-injection configuration


    【解决方案1】:

    您定义的 bean 是一个 Singleton,因此它是在应用程序知道任何人都可能自动装配该值之前在上下文初始化时创建的。您必须将 Bean 创建为 Prototype 才能仅在 autowire 上请求实例。

    这仍然无法获取有关 autowire-target 的信息。可以使用*Aware-interfaces来获取

    • 自己独特的 Beanname
    • 豆工厂
    • 应用程序上下文

    但是自动连线的target 和目标的class 都不是。

    请注意:如果 autowire-field 已标记为 @Lazy 并且 Bean 的范围是 Prototype,您可以使用 bean 的 @PostConstruct 详细说明 bean 自动装配的确切时间。

    【讨论】:

      【解决方案2】:

      我不确定你为什么要这样做,但这似乎是个坏主意。

      类不应该围绕调用者配置它们的行为,这会导致代码紧密耦合且移植性不强。

      相反,您应该找出使这 2 个字段不同的原因,并将它们重构为使用 2 个不同的接口(在共享功能的情况下,它们甚至可能有一个通用的超级接口)。然后,您可以轻松地为这些接口提供 2 种不同的实现。在您的情况下,您还可以编写一个类来处理 id == 7 的特定情况和其他情况(可能通过委托),并在将其注入 A 之后或同时使用另一种配置实例的方式。

      我不知道有任何可能直接做你想做的事。

      编辑:在 cmets 中进一步讨论并了解更多您想要完成的任务后,我认为最好有一个工厂来创建 A 实例:

      @Service
      class AFactory {
      
          @Autowired
          private SpecificSomeClassImplForId7 specificSomeClassImplForId7;
      
          @Autowired
          private SomeClass someClass;
      
          public A makeA() {
              if(isSpecialA()) {
                  return new A(specificSomeClassImplForId7);
              } else {
                  return new A(someClass);
          }
      }
      

      那么你就可以在你的Application中的其他Spring Beans中使用这个工厂来制作As了。

      【讨论】:

      • 谢谢。我正在尝试做的(也许 DI 不是正确的方法)是构建一个基于接口和不同实现的实例树。 A 类的实例需要有一个 SomeClass 子级,但并不总是相同的实例,也不一定总是相同的实现。
      • 一个很好的例子是 Car 类,它有四个轮子,每个轮子都有一层。前轮配备Miche 型轮胎,压力为 30 PSI。后轮有宽 GoodY 轮胎,压力为 28 PSI。我想从文件中读取此配置,并为不同的汽车配置不同的轮胎组,并且每个车轮的配置根据它所在的汽车以及该汽车实例的前轮还是后轮进行不同的配置。
      • 我明白了。在这种情况下,您可能希望 As 可以直接访问应用程序上下文并自己搜索正确的实现。您可以自动装配 ApplicationContext 类,然后让 A 选择正确的轮胎。不过,轮胎不应该与他们所驾驶的汽车有关。
      • 谢谢。也许。事实上,轮胎不应该知道它们属于哪辆车。我希望需要为汽车提供轮胎的机械师(@Configuration 类)变得更智能。因此,它会检查它是哪种类型的汽车,并检查它是前轮还是后轮的层,并检查购买该特定汽车实例的客户是否有特殊要求。然后,机械师可以构建合适的等级,或者从货架上拿一个,并为特定的汽车、特定的车轮提供它。
      • 我明白你在说什么。也许那时将依赖项注入汽车确实不是正确的方法。相反,您可以编写一个 Factory 类,该类将注入所有不同的轮胎实现,然后它可以决定如何构建汽车,而不是让 Spring 构建它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多