Java 如何使用带构造函数参数的Spring原型bean?

Java 如何使用带构造函数参数的Spring原型bean?,java,spring,design-patterns,lombok,Java,Spring,Design Patterns,Lombok,我用的是弹簧和龙眼。 没有原型bean,我们必须传递目标类所需的依赖项。 如何将bean标记为原型并正确处理依赖bean和构造函数参数 选项1-没有原型bean @Component @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class Consumer { private final SomeDependency iDontNeed; // Consumer class doesn't need p

我用的是弹簧和龙眼。 没有原型bean,我们必须传递目标类所需的依赖项。 如何将bean标记为原型并正确处理依赖bean和构造函数参数

选项1-没有原型bean

@Component @RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Consumer {
  private final SomeDependency iDontNeed; // Consumer class doesn't need
  private final SomeDependency2 iDontNeed2;

  public void method() {
    new Processor("some random per request data", iDontNeed, iDontNeed2);
  }
....
@Value @RequiredArgsConstructor
public class Processor {
  private final String perRequestInputData;
  private final SomeDependency iReallyNeed;
  private final SomeDependency2 iReallyNeed2;
}
选项2-原型bean

@Component @RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Consumer {
  private final Provider<Processor> processorProvider;

  public void method() {
    Processor p = processorProvider.get();
    p.initializeWith("some random per request data");
  }
....
@Component @Scope("prototype") 
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Processor {
  private final SomeDependency iReallyNeed;
  private final SomeDependency2 iReallyNeed2;

  private String perRequestInputData; //wish I was final
  private boolean initialized; //wish I was not needed

  public void initializeWith(String perRequestInputData) {
    Preconditions.checkState(!initialized);
    this.perRequestInputData = perRequestInputData
    initialized = true;
  }
}
我的评论:

备选案文1:

它干净而简单。并非每个类都需要声明为Springbean。如果一个类足够简单,不使用任何Spring特性,如@Cache、@Tranascational等,那么可以亲吻它,不将其声明为Springbean并手动创建它。消费者就像驱动逻辑的主类一样,所以我想说消费者在某种意义上也需要依赖关系,因为它需要它们来驱动创建处理器的逻辑

备选案文2:

我同意你的看法。不太好,因为我们需要单独的调用和额外的initialized属性,以确保与选项1(我们只需要通过构造函数创建)相比,处理器被正确创建。但处理器是一个Springbean,所以我们可以很容易地将Spring特性应用于它

我们有其他选择吗

我的另一种选择是将工厂模式与@Configuration和@Bean结合使用,以实现这两个方面的最佳效果:

首先定义工厂:

@Configuration
public class ProcessorFactory {

     @Autowired
     private final SomeDependency dep1; 

     @Autowired
     private final SomeDependency2 dep2;

     @Bean(autowireCandidate = false)
     @Scope("prototype") 
     public Processor createProcessor(String requestData) {
        return new Processor(requestData, dep1, dep2);
    }
}
然后在消费者中:

@Component
public class Consumer {

     @Autowired 
     private final ProcessorFactory processorFactory;


      public void method() {
        Processor p = processorFactory.createProcessor("some random per request data");
        p.blablbaba();
      }
}

注意:@BeanautowireCandidate=false在处理器@Bean上是必需的。否则,Spring将尝试查找字符串类型的bean,以便在启动期间创建处理器。由于没有字符串类型的bean,它将抛出异常。将autowireCandidate设置为false可以禁用Spring创建它。毕竟,我们将通过ProcessorFactory手动创建它

我假设您收到了反对票,因为关于小邪恶的问题完全是主观的。也许可以用不变性和其他你想要实现的东西来重新表述这个问题。我同意@jaco0646。这个问题的措辞可以征求意见,但完全可以客观地回答。这是一个需要调整的好问题。您可以在中找到答案。感谢您的反馈,我已经重新编写了我的问题。请注意,在我对OP的评论中,Spring已经通过其BeanFactory接口实现了此工厂模式。滚动您自己的工厂的优点包括围绕运行时参数的类型安全性以及消除使用者中的Spring依赖性。这只需要你多上一节课。这是一个有效的例子吗?请更新工厂类中的void。另外,如何在factory类中读取字符串requestData?它显示错误无法为我自动连线。捕捉良好。在定义原型bean时,让我们尝试使用@BeanautowireCandidate=false。您好@ken,我使用了autowireCandidate=false,我仍然获得了所需的类型为“java.lang.String”的bean,但找不到该bean。你知道为什么吗?Hello@AdiV你找到这个问题的解决方案了吗?