spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.36k stars 40.51k forks source link

Ease the creation of multiple task executor and task scheduled builders #39928

Open frosiere opened 5 months ago

frosiere commented 5 months ago

Through an auto-configuration, Spring Boot makes it easy to create a task executor builder and a task scheduled builders with their respective sets of properties.

In most cases, this is sufficient, but in some specific cases, it may be necessary to create multiple builders with multiple sets of properties. In this case, the configuration has to be defined manually, resulting in some duplication of Spring Boot code.

It would be great if Spring Boot could provide an easy way to create these builders from a given property class.

Let's take a concrete example. Suppose an application needs to create 2 ThreadPoolTaskSchedulerBuilder with 2 sets of properties. The support could be given as follows

TaskSchedulingProperties taskSchedulingProperties1 = new TaskSchedulingProperties();
ThreadPoolTaskSchedulerBuilder taskSchedulerBuilder1 = xxx.create(taskSchedulingProperties);

TaskSchedulingProperties taskSchedulingProperties2 = new TaskSchedulingProperties();
ThreadPoolTaskSchedulerBuilder taskSchedulerBuilder2 = xxx.create(taskSchedulingProperties);

xxx could either be a factory, a utility class or a static method on the property class itself.

Our use case is to create several builders in different contexts such as grpc, kafka, etc.

In previous versions of Spring boot, it was possible to abuse the use of auto-configurations as follows

    TaskExecutorBuilder createTaskExecutorBuilder(TaskExecutionProperties properties) {
        return new TaskExecutionAutoConfiguration().taskExecutorBuilder(
                properties, 
                new EmptyObjectProvider<>(), 
                new EmptyObjectProvider<>()
        );
    }
    TaskSchedulerBuilder createTaskSchedulerBuilder(TaskSchedulingProperties properties) {
        return new TaskSchedulingAutoConfiguration().taskSchedulerBuilder(
                properties, 
                new EmptyObjectProvider<>()
        );
    }

Any feedback or comments are more than welcome.

mhalbritter commented 5 months ago

Just FYI: we don't consider the auto-configurations public API (only their names), so something like this:

 return new TaskExecutionAutoConfiguration().taskExecutorBuilder(

is absolutely not recommended.

frosiere commented 5 months ago

Just FYI: we don't consider the auto-configurations public API (only their names), so something like this:

 return new TaskExecutionAutoConfiguration().taskExecutorBuilder(

is absolutely not recommended.

Thanks for the quick reply. Fully agree, it's an abusive usage of an internal API (just gave it as an "example"). That's why I created this issue to achieve our use case in a nice way without having to copy code.

scottfrederick commented 5 months ago

We've had several issues in the past that are similar to this one, in that they express a desire to make it easier to create multiple beans of a given type without having to duplicate Spring Boot's auto-configuration code. #22403 and #35157 are examples. #21322 has been referenced as a possible solution for cases where the beans are connections to external services, but that would not apply to requirements like the one in this issue. So, this feels like a duplicate but I'm not sure any of the existing issues captures the general requirements.

frosiere commented 5 months ago

Thank you for your reply. I checked the other issues, the use case seems similar but not identical, and these issues are also quite old. It seems difficult to have a general approach that works in all cases.

So, couldn't we try to apply the following approach: if a complex object can directly be built from a configuration properties class, wouldn't it make sense to expose a factory method on that class?

Concrete example

        TaskExecutionProperties taskExecutionProperties = new TaskExecutionProperties();
        TaskExecutorBuilder taskExecutorBuilder = taskExecutionProperties.create();

Another approach might be to use a configurer or a customizer, but I'm not sure that's the best fit.

philwebb commented 4 months ago

We discussed this today and we think this is a general problem that we need to invest some time designing. The general pattern of creating an object from properties comes up again and again.