今天debug代码时,遇到一个坑
public interface LoopService {
void testLoop();
void testInnerLoop();
}
@Service
public class DefaultLoopService implements LoopService {
private static final Logger log = LoggerFactory.getLogger(DefaultLoopService.class);
@Override
public void testLoop() {
log.info("DefaultLoopService");
}
@Override
public void testInnerLoop() {
log.info("DefaultLoopService--testInnerLoop");
}
}
@Service
@Primary
public class UsingLoopService implements LoopService {
private static final Logger log = LoggerFactory.getLogger(UsingLoopService.class);
@Autowired
private LoopService loopService;
@Override
public void testLoop() {
log.info("UsingLoopService");
loopService.testInnerLoop();
}
@Override
public void testInnerLoop() {
log.info("UsingLoopService--testInnerLoop");
}
}
@RestController
public class LoopController {
@Autowired
private LoopService loopService;
@GetMapping("/testLoop")
public void testLoop() {
loopService.testLoop();
}
}
当我请求http://localhost:8080/testLoop时,
期望打印
UsingLoopService : UsingLoopService
UsingLoopService : UsingLoopService–testInnerLoop
但实际却打印
UsingLoopService : UsingLoopService
UsingLoopService : DefaultLoopService–testInnerLoop
我的解决方案
给UsingLoopService命名
@Service("usingLoopService")
@Primary
public class UsingLoopService implements LoopService {
private static final Logger log = LoggerFactory.getLogger(UsingLoopService.class);
@Autowired
@Qualifier("usingLoopService")
private LoopService loopService;
@Override
public void testLoop() {
log.info("UsingLoopService");
loopService.testInnerLoop();
}
@Override
public void testInnerLoop() {
log.info("UsingLoopService--testInnerLoop");
}
}
这时打印符合预期
UsingLoopService : UsingLoopService
UsingLoopService : UsingLoopService–testInnerLoop
请教
哪位大神有更好的解决方案,不防写在下面评论区↓\downarrow↓
后续
今天收到了spring官方的回复
the logic locates in org.springframework.beans.factory.support.DefaultListableBeanFactory@L1533
//以下代码摘自spring源码
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match
* the required type (never {@code null})
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}