如何使用带有构造函数参数的 Spring Prototype Beans?

Ram*_*Ram 0 java spring design-patterns lombok

我确实使用 Spring 和 Lombok。
如果没有原型 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;
}
Run Code Online (Sandbox Code Playgroud)

选项 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

Ken*_*han 5

我的评论:

选项1:

它干净简单。并非每个类都需要声明为 Spring bean。如果一个类足够简单,不使用任何 Spring 特性(例如@Cache@Tranascational等),那么 KISS 并且不将其声明为 Spring bean 并手动创建它是可以的。该Consumer就像主类驱动逻辑,所以我会说SomeDependency,还需要通过Consumer,因为它需要它们来驱动创建的逻辑在某种意义上Processor

选项 2:

同意您。不太好,因为我们需要单独的调用和额外的“初始化”属性,以确保与我们只需要通过构造函数创建它的选项 1 相比正确创建处理器。但是它Processor是一个 Spring bean,因此我们可以很容易地将 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在消费者中:

@Component
public class Consumer {

     @Autowired 
     private final ProcessorFactory processorFactory;


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

注:@Bean(autowireCandidate = false)Processor@Bean是必要的。否则,Spring 将在启动期间尝试寻找 String 类型的 bean 来创建 Processor。由于没有 String 类型的 bean,它会抛出异常。设置autowireCandidate为 false 可以禁用 Spring 创建它。毕竟,我们将通过手动从ProcessorFactory