Одни и те же данные применяются ко всем компонентам одного типа при создании списка компонентов с различными данными. - PullRequest
0 голосов
/ 01 июня 2018

Мой вариант использования - создать список бинов «B», каждый из которых имеет свой экземпляр зависимого бина «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.
}

При создании списка B в bPool при построении (Iпроверяется путем печати в пост-конструкции), каждый экземпляр B устанавливается для каждого B соответственно.

Однако при использовании экземпляров B позже из того же пула все экземпляры B имеют одинаковый Cinstance.

Все они имеют экземпляр C, для которого был установлен последний созданный элемент B в bPool.

Я новичок в Springboot и не могу понять это поведение.Любая помощь приветствуется.Спасибо

1 Ответ

0 голосов
/ 06 июня 2018

Все еще не уверены, что является причиной проблемы.Однако другой подход решил мой вариант использования.

Я пошел дальше и использовал функцию Async, предоставляемую самой Spring.

См .: ссылка на документацию

  1. В своем основном классе добавьте аннотацию @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. Создайте новый класс с помощью открытого метода с @Асинхронная аннотация, содержащая тяжелый код, который мы хотим запустить в фоновом режиме.Этот метод должен быть общедоступным и должен находиться в другом классе для работы с прокси.Мы не можем создать этот асинхронный метод в том же классе, откуда он будет вызван.

    @Component
    public class MyAsyncService {
    
        @Async
        public CompletableFuture<ResultClass> myAsyncMethod(String params){
            //do some heavy tasks here
            return CompletableFuture.completedFuture(instanceOfResultClass);
        }
    }
    
  3. Вызовите вышеуказанный класс с помощью асинхронного метода из класса вызывающего.

    @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();
        }
    }
    
...