Several ways of getBean() in Spring (reproduced)

1 Introduction

In this article, we will detail the various ways of obtaining beans from the BeanFactory.

Simply put, getBean() is responsible for getting the bean instance from the Spring IOC container, as the method's name suggests.

2. Create a bean container

First, let's define some Spring beans for testing. There are many ways to create a spring IOC container, but in this article, we will use annotation-based Java configuration:

@Configuration
class AnnotationConfig {
    
    
 
    @Bean(name = {
    
    "tiger", "kitty"})
    @Scope(value = "prototype")
    Tiger getTiger(String name) {
    
    
        return new Tiger(name);
    }
 
    @Bean(name = "lion")
    Lion getLion() {
    
    
        return new Lion("Hardcoded lion name");
    }
 
    interface Animal {
    
    }
}

We create two beans. Lion has a default singleton scope. Tiger is explicitly set as prototype. In addition, we define names for each bean that will be used in subsequent instances.

3. getBean() API

BeanFactory provides 5 methods of getBean() method, which we will study in the following subsections.

3.1. Get Bean by name

Let's see how to get a Lion Bean instance by name:

Object lion = context.getBean("lion");
 
assertEquals(Lion.class, lion.getClass());

In this method, we get the bean based on the bean name, and return the instance of the Object class if the bean exists in the spring ico container. Otherwise, the following exception is thrown

NoSuchBeanDefinitionException。

The main disadvantage is that after getting the bean we have to cast it to the required type. An exception may be raised if the returned bean is of a different type than we expected.

Let's say we're trying to get "lion" with the name "tiger". When we cast the result to lion, it throws a ClassCastException:

assertThrows(ClassCastException.class, () -> {
    
    
    Tiger tiger = (Tiger) context.getBean("lion");
});

3.2. Get Bean by name and type

Here we need to specify the name and type of the requested bean:

Lion lion = context.getBean("lion", Lion.class);

Compared with the 3.1 method, this method is safer because we can find errors at the compile stage instead of at the runtime stage.

assertThrows(BeanNotOfRequiredTypeException.class, () -> 
    context.getBean("lion", Tiger.class));
}

3.3. Get Bean by type

The third way using getBean(), just specifying the bean type is enough

Lion lion = context.getBean(Lion.class);

In this case, we need to pay special attention to possible ambiguities:

assertThrows(NoUniqueBeanDefinitionException.class, () -> 
    context.getBean(Animal.class));
}

In the example above, since both Lion and Tiger implement the Animal interface, specifying the type alone is not sufficient to unambiguously determine the result. So we get one NoUniqueBeanDefinitionException. That is, in the same IOC container, if there are multiple beans of the same type, the beans cannot be obtained by type.

3.4. Filter beans by name and constructor parameters

In addition to the bean name, we can also pass constructor parameters:

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian");

This method is a bit different as it only works for beans with prototype scope.

In case of singleton, we will get BeanDefinitionStoreException.

Because the prototype bean, every time the bean is obtained from the spring ioc container, a newly created instance will be returned, so we can dynamically provide the constructor parameters when calling getBean():

Tiger tiger = (Tiger) context.getBean("tiger", "Siberian");
Tiger secondTiger = (Tiger) context.getBean("tiger", "Striped");
 
assertEquals("Siberian", tiger.getName());
assertEquals("Striped", secondTiger.getName());

As we can see, each Tiger has a different name based on the second parameter we specified when requesting the bean.

3.5. Filter beans by type and constructor parameters

This method is similar to the previous one, but we need to pass a type instead of a name as the first argument:

Tiger tiger = context.getBean(Tiger.class, "Shere Khan");
 
assertEquals("Shere Khan", tiger.getName());

Similar to 3.4, this method only works for beans with prototype scope.

4. Precautions for use

Although getBean() is defined in the BeanFactory interface, most of the getBean() methods are accessed through ApplicationContext. Usually, we don't want to use the getBean() method directly in the application.

Beans should be managed by the container. If we want to use one of them, we should rely on dependency injection instead of calling ApplicationContext.getBean() directly. This way, we avoid mixing application logic with framework-related details.

5 Conclusion

In this quick tutorial, we went through all the implementations of the getBean() method from the BeanFactory interface and described the advantages and disadvantages of each method.

Author: Siege Lion susht
Link: https://www.jianshu.com/p/ba6610930b01
Source: Jianshu

Guess you like

Origin blog.csdn.net/qq_43575801/article/details/128832589