java - Which ThreadPoolTaskExecutor bean is autowired when multiple Executors exist in Spring configuration? - Stack Overflow

I'm configuring multiple ThreadPoolTaskExecutor in Spring and encountering ambiguity in bean autow

I'm configuring multiple ThreadPoolTaskExecutor in Spring and encountering ambiguity in bean autowiring. I need help understanding the injection behavior.

Configuration class:

@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {
    public static final String COMMON_EXECUTOR = "commonExecutor";
    public static final String TEST_EXECUTOR = "testExecutor";

    @Override
    public Executor getAsyncExecutor() {
        return commonExecutor();
    }

    @Primary
    @Bean(COMMON_EXECUTOR)
    public ThreadPoolTaskExecutor commonExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // Configuration details...
        return executor;
    }

    @Bean(TEST_EXECUTOR)
    public ThreadPoolTaskExecutor testExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // Different configuration...
        return executor;
    }
}

Service class:

@Slf4j
@Service
@RequiredArgsConstructor
public class WareVarietyServiceImpl implements WareVarietyService {
    private final ThreadPoolTaskExecutor testExecutor;
}

There are two ThreadPoolTaskExecutor beans defined: commonExecutor (marked with @Primary) and testExecutor. When autowiring testExecutor in the service class:

Expected: Injection of the testExecutor bean specifically.

Actual: Injection of the commonExecutor bean specifically.

I'm configuring multiple ThreadPoolTaskExecutor in Spring and encountering ambiguity in bean autowiring. I need help understanding the injection behavior.

Configuration class:

@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {
    public static final String COMMON_EXECUTOR = "commonExecutor";
    public static final String TEST_EXECUTOR = "testExecutor";

    @Override
    public Executor getAsyncExecutor() {
        return commonExecutor();
    }

    @Primary
    @Bean(COMMON_EXECUTOR)
    public ThreadPoolTaskExecutor commonExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // Configuration details...
        return executor;
    }

    @Bean(TEST_EXECUTOR)
    public ThreadPoolTaskExecutor testExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // Different configuration...
        return executor;
    }
}

Service class:

@Slf4j
@Service
@RequiredArgsConstructor
public class WareVarietyServiceImpl implements WareVarietyService {
    private final ThreadPoolTaskExecutor testExecutor;
}

There are two ThreadPoolTaskExecutor beans defined: commonExecutor (marked with @Primary) and testExecutor. When autowiring testExecutor in the service class:

Expected: Injection of the testExecutor bean specifically.

Actual: Injection of the commonExecutor bean specifically.

Share Improve this question edited Mar 25 at 16:42 dani-vta 7,5357 gold badges49 silver badges65 bronze badges asked Mar 25 at 11:44 一生热爱一生热爱 211 bronze badge 1
  • did the post answer your question or are you still having touble with it? – dani-vta Commented Apr 5 at 10:11
Add a comment  | 

2 Answers 2

Reset to default 0

the @Primary executor bean is going to be injected.

If you were to remove @Primary then it will try to match by bean name (default bean name is the method name = testExecutor) and for that to work you would need to use @Qualifier("testExecutor"):

public class WareVarietyServiceImpl implements WareVarietyService {
    @Autowired 
    @Qualfier("testExecutor")
    private ThreadPoolTaskExecutor testExecutor;
}

Without @Qualfier it will throw an exception because 2 beans of same type are defined without @Primary or @Qualifier annotations present

See relevant documentation

Spring offers different ways of injecting dependencies. Some examples are @Autowired, @Inject, and @Resource, where each annotation provides a different wiring mechanism. In your case, you should first understand which annotation is applied implicitly under the hood.

Since Spring 4.3, when a class provides a single constructor, this is automatically annotated with @Autowired. Quoting an extract from the Spring docs Using @Autowired:

As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if several constructors are available and there is no primary/default constructor, at least one of the constructors must be annotated with @Autowired in order to instruct the container which one to use.

In your case, since WareVarietyServiceImpl offers only a single constructor due to Lombok's @RequiredArgsConstructor, Spring automatically applies the annotation @Autowired to it. Therefore, your class is equivalent to:

@Slf4j
@Service
public class WareVarietyServiceImpl implements WareVarietyService {
    private final ThreadPoolTaskExecutor testExecutor;

    @Autowired
    public WareVarietyServiceImpl(ThreadPoolTaskExecutor testExecutor) {
        this.testExecutor = testExecutor;
    }
}

Now that we know which autowiring mechanism is used, we can break down what actually happens. @Autowired injects dependencies by type; therefore, both beans commonExecutor and testExecutor are valid candidates to be injected into WareVarietyServiceImpl.

However, in your code, you're also using @Primary to annotate the bean definition commonExecutor. This annotation basically marks a bean as the one to favorite when concurring for injection with other candidates. Quoting the docs:

@Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one primary bean exists among the candidates, it becomes the autowired value.

This explains why commonExecutor is injected, even though WareVarietyServiceImpl's field shares the same name of the bean definition testExecutor. If you want WareVarietyServiceImpl to be injected with testExecutor, either use @Resource which matches by name first and by type second, or @Qualifier which narrows down a set of type matches by a qualifying value. If no qualifying value is provided to a bean definition, the bean's name is used as a default qualifier.

@Resource Solution

@Slf4j
@Service
@RequiredArgsConstructor
public class WareVarietyServiceImpl implements WareVarietyService {
    @Resource
    private final ThreadPoolTaskExecutor testExecutor;
}

@Qualifier Solution

@Slf4j
@Service
public class WareVarietyServiceImpl implements WareVarietyService {
    private final ThreadPoolTaskExecutor testExecutor;

    @Autowired
    public WareVarietyServiceImpl(@Qualifier(ThreadPoolConfig.TEST_EXECUTOR) ThreadPoolTaskExecutor testExecutor) {
        this.testExecutor = testExecutor;
    }
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744198759a4562781.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信