容器中定义的Bean概述


Spring IoC 容器管理一个或多个bean 。这些bean 是使用您提供给容器的配置元数据创建的(例如,以XML `定义的形式)。

​ 在容器本身内,这些bean定义表示为BeanDefinition对象,其中包含(除其他信息外)以下元数据:

1. 包限定的类名称:通常,定义了`Bean`的实际实现类。
2. `Bean`行为配置元素,用于声明`Bean`在容器中的行为(作用域,生命周期回调等)。
3. 引用该`bean`完成其工作所需的其他`bean`。这些引用也称为协作者或依赖项。
4. 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在管理连接池的`bean`中要使用的连接数。

该元数据转换为构成每个bean定义的一组属性。下表描述了这些属性:

Bean 中的属性注释
ClassBean的实现类的包路径的完全限定名
NameBean 定义的名称
ScopeBean的作用域,默认是singleton单例的
Constructor argumentsBean实现类中的构造器需要的参数列表
PropertiesBean实现类定义的域,即类中的成员属性
Autowiring modeBean实现类中的域依赖注入的方式(例如,byType按类型注入等)
Lazy initialization modeBean定义是否为懒加载,即知道这个Bean被调用的时候才去实例化这个对象
Initialization methodBean生命周期回调中的初始化方法
Destruction methodBean生命周期回调中的销毁方法

​ 除了包含有关如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过通过getBeanFactory()方法访问ApplicationContextBeanFactory来完成的,该方法返回BeanFactory DefaultListableBeanFactory实现。 DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持此注册。但是,典型的应用程序只能与通过常规bean定义元数据定义的bean一起使用。

1.3.1 如何给Bean命名

​ 每个bean具有一个或多个标识符。这些标识符在承载Bean的容器内必须唯一。一个bean通常只有一个标识符。但是,如果需要多个,则可以将多余的别名视为别名。

​ 在基于XML的配置元数据中,可以使用id属性和/或name属性来指定Bean标识符。 id属性可让您精确指定一个id。按照惯例,这些名称是字母数字(“ myBean”,“ someService”等),但它们也可以包含特殊字符。如果要为bean引入其他别名,则还可以在name属性中指定它们,并用逗号(,),分号(;)或空格分隔。作为历史记录,在Spring 3.1之前的版本中,id属性定义为xsd:ID类型,该类型限制了可能的字符。从3.1开始,它被定义为xsd:string类型。请注意,bean ID唯一性仍由容器强制执行,尽管不再由XML解析器执行。

​ 您可以不提供bean的名称或ID。如果未明确提供名称或ID,则容器将为该bean生成一个唯一的名称。但是,如果要按名称引用该bean,则通过使用ref元素或服务定位器样式查找,必须提供一个名称。

​ 在命名bean时将标准Java约定用于实例字段名称。也就是说,bean名称以小写字母开头,并从那里用驼峰式大小写。

  • 不通过Bean属性中的Name属性来定义别名,而使用<alias name ="xxx" alias = "xxx"/>

    ​ 在bean定义本身中,可以使用由id属性指定的最多一个名称和name属性中任意数量的其他名称的组合为bean提供多个名称。这些名称可以是同一个bean的等效别名,并且在某些情况下很有用,例如,通过使用特定于该组件本身的bean名称,让应用程序中的每个组件都引用一个公共依赖项。

    ​ 但是,在实际定义bean的地方指定所有别名并不总是足够的。有时需要为在别处定义的bean引入别名。这在大型系统中通常是这种情况,在大型系统中,配置在每个子系统之间分配,每个子系统都有自己的对象定义集。在基于XML的配置元数据中,可以使用<alias />元素来完成此操作。以下示例显示了如何执行此操作:

    <alias name="fromName" alias="toName"/>
    

    ​ 在这种情况下,在使用该别名定义之后,也可以将名为fromNamebean(在同一容器中)称为toName

    ​ 例如,子系统A的配置元数据可以通过子系统A-dataSource的名称引用数据源。子系统B的配置元数据可以通过子系统B-dataSource的名称引用数据源。组成使用这两个子系统的主应用程序时,主应用程序通过myApp-dataSource的名称引用数据源。要使所有三个名称都引用同一个对象,可以将以下别名定义添加到配置元数据中:

    <alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
    <alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
    

    ​ 现在,每个组件和主应用程序都可以通过唯一的名称引用数据源,并且可以保证不与任何其他定义冲突(有效地创建名称空间),但是它们引用的是同一bean

1.3.2 如何实例化一个Bean

Bean定义实质上是创建一个或多个对象的方法。容器在被询问时会查看命名bean的配方,并使用该bean定义封装的配置元数据来创建(或获取)实际对象。

​ 如果使用基于XML的配置元数据,则在<bean />元素的class属性中指定要实例化的对象的类型(或类)。这个class属性(在内部是BeanDefinition实例的Class属性)通常是必需的。

​ 如果需要实例化的是一个内部类该怎么表示Class属性的值

​ 如果要为静态嵌套类配置Bean定义,则必须使用嵌套类的二进制名称。

​ 例如,如果您在com.example包中有一个名为SomeThing的类,并且此SomeThing类具有一个名为OtherThing的静态嵌套类,则bean定义上的class属性的值为com.example.SomeThing $ OtherThing。

​ 请注意,名称中使用$字符将嵌套的类名与外部类名分开。

  • 使用构造函数实例化

    ​ 当通过构造方法创建一个bean时,所有普通类都可以被Spring使用并兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定bean类就足够了。但是,根据您用于该特定beanIoC的类型,您可能需要一个默认(空)构造函数。

    Spring IoC容器几乎可以管理您要管理的任何类。它不仅限于管理真正的JavaBean。大多数Spring用户更喜欢实际的JavaBean,它仅具有默认(无参数)构造函数,并具有根据容器中的属性建模的适当的settergetter。您还可以在容器中具有更多奇特的非bean样式类。例如,如果您需要使用绝对不符合JavaBean规范的旧式连接池,则Spring也可以对其进行管理。

    ​ 使用基于XML的配置元数据,您可以如下指定bean类:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
            <bean id="testBean"
      class="springioc.coretechnologic.ioc.annotationbasecontainerconfig.TestBean">
            </bean>
    </beans>
    
  • 使用静态工厂方法实例化

    ​ 定义使用静态工厂方法创建的bean时,请使用class属性指定包含静态工厂方法的类,并使用名为factory-method的属性指定工厂方法本身的名称。您应该能够调用此方法(使用可选参数,如稍后所述)并返回一个活动对象,该对象随后将被视为已通过构造函数创建。这种bean定义的一种用法是在旧版代码中调用静态工厂。

    ​ 以下示例显示了如何使用静态工厂方法实例化对象:

    XML中声明该类的元数据

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
            <bean id="testBean"
      class="springioc.coretechnologic.ioc.annotationbasecontainerconfig.TestBean"
                  factory-method="getInstance">
            </bean>
    </beans>
    

    ​ 在上述class指定的具体实现类中声明静态工厂方法

    public class TestBean {
    
        private static final TestBean TEST_BEAN = new TestBean();
    
        private TestBean() {
            // no get call
        }
    
        public static TestBean getInstance(){
            return TEST_BEAN;
        }
    }
    
  • 使用实例工厂方法实例化

    ​ 类似于通过静态工厂方法进行实例化,使用实例工厂方法进行实例化会从容器中调用现有bean非静态方法来创建新bean。要使用此机制,请将class属性保留为空,并在factory-bean属性中,在包含要创建该对象的实例方法的当前(或父或祖先)容器中指定bean的名称。使用factory-method属性设置工厂方法本身的名称。以下示例显示了如何配置此类Bean

    XML中元数据的设置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
            <bean id="testBean"
     class="springioc.coretechnologic.ioc.annotationbasecontainerconfig.TestBean">
            </bean>
            <!-- 同一个factory-bean 实例 可以实例化多个对象 -->
            <bean id="testBeanB"
                  factory-bean="testBean"
                  factory-method="getInstanceB">
            </bean>
            <bean id="testBeanA"
                  factory-bean="testBean"
                  factory-method="getInstanceA">
            </bean>
    </beans>
    

    ​ 实力工厂方法的设置

    public class TestBean {
    
        private static TestBeanB testBeanB = new TestBeanB();
        private static TestBeanA testBeanA = new TestBeanA();
    
        public TestBean() {
    
        }
    
        //    同一个factory-bean 实例 可以实例化多个对象
        public TestBeanB getInstanceB() {
            return testBeanB;
        }
    
        public TestBeanA getInstanceA() {
            return testBeanA;
        }
    }
    
  • 确定Bean的运行时类型

    ​ 确定特定bean的运行时类型并非易事。 Bean元数据定义中的指定类只是初始类引用,可能与声明的工厂方法结合使用,或者是FactoryBean类,这可能导致Bean的运行时类型不同,或者在实例的情况下完全不进行设置级工厂方法(通过指定的factory-bean名称解析)。此外,AOP代理可以使用基于接口的代理包装Bean实例,而目标Bean的实际类型(仅是其实现的接口)的暴露程度有限。

    ​ 找出特定bean的实际运行时类型的推荐方法是对指定bean名称的BeanFactory.getType调用。这考虑了上述所有情况,并返回了针对相同bean名称的BeanFactory.getBean调用将返回的对象的类型。

参考文献

【https://docs.spring.io/spring-framework/docs/current/reference/html/core.html】【1.3. Bean Overview】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值