spring version: 6.2.10

two circular reference:


@Component
@Order(1)
public class TestA {
    @Autowired
    private TestB testB;

    private String name;
// get and set

    public String hello () {
        return "hello A" + this.getName();
    }

    public String otherName () {
        return testB.getName();
    }
}


@Component
@Order(1)
public class TestB {
    @Autowired
    private TestA testA;

    private String name;
// get and set

    public String hello () {
        return "hello B" + this.getName();
    }

    public String otherName () {
        return testA.getName();
    }
}

postprocessor:

@Component
public class BugPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (TestA.class.isAssignableFrom(bean.getClass())) {
            System.out.println("Modifying TestA bean before initialization");
            return new TestA(); // use another object to replace it
        }
        if (TestB.class.isAssignableFrom(bean.getClass())) {
            System.out.println("Modifying TestB bean before initialization");
            return new TestB(); // use another object to replace it
        }
        return bean; // return original bean
    }
}

AOP:

@Aspect
@Component
public class AOPConfig {

    @Pointcut("execution(* com.voidvvv.issue.service.*.*(..))" )
    public void pointCut() {}

    @Before("pointCut()")
    public void before() {
        System.out.println("AOP before");
    }
}

controller

@RestController
@Lazy
@RequestMapping("/test")
public class TestController {
    @Autowired
    private TestA testA;

    @Autowired
    private TestB testB;

    @GetMapping("/show")
    public String show() {
        StringBuilder sb = new StringBuilder();
        sb.append("show TestA: " + testA.hello() + "\t\n");
        sb.append(System.lineSeparator());
        sb.append("show TestB: " + testB.hello() + "\t");
        sb.append(System.lineSeparator());
        sb.append("show TestB in TestA: " + testA.otherName() + "\t");
        sb.append(System.lineSeparator());
        sb.append("show TestA in TestB: " + testB.otherName() + "\t");
        sb.append(System.lineSeparator());
        return sb.toString();
    }
}

confiuration:

spring.main.allow-circular-references=true

exception: we can successfully start up the application. then we request : http://localhost:8080/test/show, we will get a NPE in TestA, the TestB object in TestA is null.

exceptation: we need get an error when we start up the application since we have illegal beans in our application.

minimal demo: https://github.com/voidvvv/spring_bean_issue

I use springboot 3.5.5 in this demo to represent this issue.

Comment From: voidvvv

the root cause analysis is in the minimal demo.