在创建具有不同数据的 bean 列表时,相同数据应用于所有相同类型的 Bean

Same Data applied across all Beans of same type while creating a list of beans with different data

我的用例是创建一个 Bean 列表 "B",每个 Bean 都有一个不同的依赖 bean 实例 "C"。

@Component("a")
public class A{

    List<B> bPool = new ArrayList<>();
    private ApplicationContext appContext;

    @Autowired 
    A(ApplicationContext appContext){
        this.appContext = appContext;
    }

    @PostConstruct
    public void init(){
        for(int i=0; i<POOL_SIZE; i++){
            bPool.add((B) appContext.getBean("b"));
        }
    }

    //code for multi-threading, which uses beans from the list bPool. 
    //I iterate the list, launch multiple threads, 
    //pass different data to each thread and combine results.
    List<CompletableFuture> multiThreads = new ArrayList<>();
    Iterator it = bPool.iterator();
    for(Data d : listOfSomeData){ //same size for listOfSomeData and bPool
        CompletableFuture var = CompletableFuture.supplyAsync(() -> {
            B curr = (B) it.next()
            curr.someMethodInB(d);
        });
        multiThreads.add(var);
    }
    multiThreads.forEach(cf -> cf.join());
}

@Component("b")
@Scope("prototype")
public class B{
    //Service class - has some dependencies, like C below
    private C c;
    private ApplicationContext appContext;

    @Autowired    
    B(ApplicationContext appContext){
        this.appContext = appContext;
    }

    @PostConstruct
    public void init(){
        c = (C) appContext.getBean("c");
    }

}

@Component("c")
@Scope("prototype")
public class C{
    //this class holds some data and does some processing on it, 
    //I want this to be different for different instances in different threads.
}

在 bPool 中创建 B 列表时,在构造时(我通过在 post-construct 中打印检查),分别为每个 B 设置了不同的 C 实例。

但是,当稍后使用同一池中的 B 实例时,所有 B 实例都具有相同的 C 实例。

它们都有 C 实例,该实例设置为 bPool 的最后创建的 B 元素。

我是 springboot 的新手,无法理解这种行为。任何帮助表示赞赏。谢谢

仍然不确定是什么导致了这个问题。然而,一种不同的方法解决了我的用例。

我继续使用 spring 本身提供的异步功能。

参考:documentation link

  1. 在您的主 class 中,添加 @EnableAsync 注释并创建后台线程池 运行。

    @SpringBootApplication
    @EnableAsync
    public class Application {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args).close();
    }
    
    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("ThreadName-");
        executor.initialize();
        return executor;
    }
    }
    
  2. 使用 public 方法创建一个新的 class 方法,@Async 注释包含我们想要在后台 运行 的繁重代码。此方法需要 public 并且必须在不同的 class 中才能使代理工作。我们无法在将调用它的同一个 class 中创建此异步方法。

    @Component
    public class MyAsyncService {
    
        @Async
        public CompletableFuture<ResultClass> myAsyncMethod(String params){
            //do some heavy tasks here
            return CompletableFuture.completedFuture(instanceOfResultClass);
        }
    }
    
    1. 使用来自调用方 class 的异步方法调用上述 class。

      @Component
      public class CallerService{
      
          private MyAsyncService myAsyncService;
      
          @Autowired
          public CallerService(MyAsyncService myAsyncService){
              this.myAsyncService = myAsyncService;
          }
      
          public void myMethod(){
              CompletableFuture<ResultClass> result1 = myService.findUser("PivotalSoftware");
              CompletableFuture<ResultClass> result2 = gitHubLookupService.findUser("CloudFoundry");        
      
              CompletableFuture.allOf(result1, result2).join();
      
              ResultClass finalResult1 = result1.get();
              ResultClass finalResult2 = result2.get();
          }
      }