Version: spring-boot-2.5.6

Code:

public interface LoopService {

    void testLoop();

    void testInnerLoop();
}
@Service
public class DefaultLoopService implements LoopService {

    private static final Logger log = LoggerFactory.getLogger(DefaultLoopService.class);

    @Autowired
    private LoopService loopService;

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

Expect Print:

service.impl.UsingLoopService : UsingLoopService
service.impl.UsingLoopService : UsingLoopService--testInnerLoop

But Actual Print:

service.impl.UsingLoopService : UsingLoopService
service.impl.DefaultLoopService : DefaultLoopService--testInnerLoop

Comment From: philwebb

I think that this is working as expected. You can't inject a bean into itself so UsingLoopService is injected with a DefaultLoopService

Comment From: mdeinum

You can't inject a bean into itself

Well actually you can (as of Spring 4.3) so you can call a method on yourself so AOP is applied (instead of using this). See https://github.com/spring-projects/spring-framework/issues/13096.

Comment From: philwebb

Thanks @mdeinum, I wasn't aware of that. It looks like that will only work if there's not another candidate to inject. I'll re-open this issue and transfer it to the Framework team to check if the behavior is expected.

Comment From: JintaoXIAO

the logic locates in org.springframework.beans.factory.support.DefaultListableBeanFactory@L1533 @daodefengshang

Comment From: snicoll

I don't think you should be doing that at all for a start. Cycles are highly discouraged and the self-injection for AOP purpose is actually a design smell. We'll share more details in https://github.com/spring-projects/spring-framework/issues/28299