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.
- did the post answer your question or are you still having touble with it? – dani-vta Commented Apr 5 at 10:11
2 Answers
Reset to default 0the @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条)