Spring IoC
容器管理一个或多个
bean
。这些
bean
是使用您提供给容器的配置元数据创建的(例如,以
XML `定义的形式)。
在容器本身内,这些bean
定义表示为BeanDefinition
对象,其中包含(除其他信息外)以下元数据:
1. 包限定的类名称:通常,定义了`Bean`的实际实现类。
2. `Bean`行为配置元素,用于声明`Bean`在容器中的行为(作用域,生命周期回调等)。
3. 引用该`bean`完成其工作所需的其他`bean`。这些引用也称为协作者或依赖项。
4. 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在管理连接池的`bean`中要使用的连接数。
该元数据转换为构成每个bean
定义的一组属性。下表描述了这些属性:
Bean 中的属性 | 注释 |
---|---|
Class | Bean 的实现类的包路径的完全限定名 |
Name | Bean 定义的名称 |
Scope | Bean 的作用域,默认是singleton 单例的 |
Constructor arguments | Bean 实现类中的构造器需要的参数列表 |
Properties | Bean 实现类定义的域,即类中的成员属性 |
Autowiring mode | Bean 实现类中的域依赖注入的方式(例如,byType按类型注入等) |
Lazy initialization mode | Bean 定义是否为懒加载,即知道这个Bean 被调用的时候才去实例化这个对象 |
Initialization method | Bean 生命周期回调中的初始化方法 |
Destruction method | Bean 生命周期回调中的销毁方法 |
除了包含有关如何创建特定bean
的信息的bean
定义之外,ApplicationContext
实现还允许注册在容器外部(由用户)创建的现有对象。这是通过通过getBeanFactory()
方法访问ApplicationContext
的BeanFactory
来完成的,该方法返回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"/>
在这种情况下,在使用该别名定义之后,也可以将名为
fromName
的bean
(在同一容器中)称为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
类就足够了。但是,根据您用于该特定bean
的IoC
的类型,您可能需要一个默认(空)构造函数。
Spring IoC
容器几乎可以管理您要管理的任何类。它不仅限于管理真正的JavaBean
。大多数Spring
用户更喜欢实际的JavaBean
,它仅具有默认(无参数)构造函数,并具有根据容器中的属性建模的适当的setter
和getter
。您还可以在容器中具有更多奇特的非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】