Background : We defined a bean by @Bean annotation in method level. Sometimes this method could return null. In the null-returning scenario, when we fetch instance by different getBean method, we found that the behaviors are different.

1, getBean(String name) It returns a real object instance of "org.springframework.beans.factory.support.NullBean". This is a spring framework inner object.

2, getBean(Class requiredType ) It throws org.springframework.beans.factory.NoSuchBeanDefinitionException

Unit test to reproduce :

public class NullBeanTest {
    @Test
    void test() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestService.class, BeanFactory.class);

        Object obj1 = ctx.getBean("nullableBean");
        assertThat(obj1.getClass().getName()).isEqualTo("org.springframework.beans.factory.support.NullBean");

        Object obj2 = ctx.getBean(NullableBean.class);
        assertThat(obj2.getClass().getName()).isEqualTo("org.springframework.beans.factory.support.NullBean");

        ctx.close();
    }

    @Component
    @Scope("prototype")
    static class TestService {

        @Autowired
        private NullableBean nullableBean;

        public NullableBean getNullableBean() {
            return nullableBean;
        }
    }

    static class NullableBean{

    }

    @Component
    static class BeanFactory {

        @Bean("nullableBean")
        @Scope("prototype")
        public NullableBean create(){
            return null;
        }
    }
}

Asks : For the null bean, we might have 3 options for the returning of getBean method

  • Option1, directly return null
  • Option2, return the instance of inner null object - org.springframework.beans.factory.support.NullBean
  • Option3, throw exception

1) From spring framework perspective, what is the official finalized behavior ? 2) Can we make the behavior consistent in each getBean method and other methods also used for getBean purpose ?

Comment From: jhoeller

We used to return null from getBean(name) before Spring Framework 5.0 there but tightened this as part of our null-safety efforts. This behavior has been in place for several years already, so we do not intend to revisit it at this point.

The reason for the different behavior is that a null bean is not of the specified required type, so not encountered as a match by getBean(type). Note that getBean(type) is effectively a type-matching retrieval method, a sort of simple version of getBeansOfType, whereas getBean(name) is a straight lookup by id. In Spring, beans are always registered by name; the type is a secondary characteristic that can be used for retrieval but does not identify a specific bean.

In practice, avoid null beans wherever you can. You might be able to conditionally register a bean instead. Pretending a bean is defined but then returning null from its factory method was always a fragile arrangement, and as of Spring Framework 5.0 we do not consider this first class anymore. We rather just tolerate it for some degree of backwards compatibility with such factory methods in existing application code. Consistent behavior is not a goal there, just tolerance of certain arrangements.