美文网首页Spring
理解Spring中的getBean()

理解Spring中的getBean()

作者: 攻城狮susht | 来源:发表于2020-04-07 18:50 被阅读0次

    1.简介

    在本文中,我们将详细介绍从BeanFactory中获取bean的多种方式。

    简单地说,正如方法的名称所表达的,getBean()负责从Spring IOC容器中获取bean实例。

    2. 创建Bean容器

    首先,让我们定义一些用于测试的Spring bean。创建spring IOC容器有多种方式,但是在本文中,我们将使用基于注释的Java配置:

    @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 {}
    }
    

    我们创建了两个bean。Lion具有默认的单例作用域。Tiger被显式地设置为prototype。另外,我们为每个bean定义了名称,这些名称将在后边的实例中使用。

    3. getBean() API

    BeanFactory提供了getBean()方法的5个方法,我们将在下面的小节中研究。

    3.1. 按名称获取Bean

    让我们看看如何使用名称获取Lion Bean实例:

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

    在此方法中,我们根据bean名称获取bean,如果在spring ico容器中存在和bean,则返回Object 类的实例。否则,抛出如下异常NoSuchBeanDefinitionException。

    主要的缺点是,在获取bean之后,我们必须将它转换为所需的类型。如果返回的bean的类型与我们期望的不同,则可能会产生异常。

    假设我们试图用“tiger”这个名字来得到“lion”。当我们将结果转换为lion时,它会抛出一个ClassCastException:

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

    3.2.通过名称和类型获取Bean

    在这里,我们需要指定所请求bean的名称和类型:

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

    与3.1的方法相比,此方法更安全,因为我们可以编译阶段就发现错误而不是在运行阶段。

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

    3.3. 按类型获取Bean

    使用getBean()的第三种方式, 仅指定bean类型就足够了

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

    在这种情况下,我们需要特别注意可能存在的歧义

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

    在上面的示例中,由于LionTiger都实现了Animal接口,因此仅指定类型不足以明确确定结果。因此,我们得到一个NoUniqueBeanDefinitionException。即在同一个IOC 容器中,如果有相同类型的多个bean,则不能通过类型获取bean。

    3.4. 按名称和构造函数参数对Bean进行筛选

    除了bean名称,我们还可以传递构造函数参数:

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

    这个方法有点不同,因为它只适用于具有原型作用域的bean。

    在单例的情况下,我们将得到BeanDefinitionStoreException异常。

    因为原型bean,每次从spring ioc容器中获取bean都会返回一个新创建的实例,所以我们可以在调用getBean()时动态地提供构造函数参数:

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

    正如我们所看到的,根据我们在请求bean时指定的第二个参数,每个Tiger都有不同的名称。

    3.5. 按类型和构造函数参数对Bean进行筛选

    此方法类似于上一个方法,但是我们需要将类型而不是名称作为第一个参数传递:

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

    与3.4相似,此方法仅适用于具有原型作用域的bean

    4.使用注意事项

    getBean()尽管是在BeanFactory接口中定义的,但是getBean()方法大部分是通过ApplicationContext访问。通常,我们在应用程序中不希望直接使用getBean()方法。

    Bean应该由容器管理。如果我们想使用它们中的一个,我们应该依赖依赖注入,而不是直接调用ApplicationContext.getBean()。这样,我们就可以避免将应用程序逻辑与与框架相关的细节混合在一起。

    5.结论

    在本快速教程中,我们从BeanFactory接口浏览了getBean() 方法的所有实现,并描述了每种方法的优缺点。

    相关文章

      网友评论

        本文标题:理解Spring中的getBean()

        本文链接:https://www.haomeiwen.com/subject/qdfophtx.html