Spring IoC容器管理一个或多个bean,这些bean是使用你提供给容器的配置元数据建立的(例如,以XML <bean/>
定义的形式)。java
在容器内部,这些bean定义被表示为BeanDefinition
对象,其中包含(其余信息)如下元数据:spring
此元数据转换为组成每一个bean定义的一组属性,下表描述了这些属性:segmentfault
属性 | 解释 |
---|---|
Class | 实例化Bean |
Name | 命名Bean |
Scope | Bean做用域 |
构造函数参数 | 依赖注入 |
属性 | 依赖注入 |
自动装配模式 | 自动装配协做者 |
延迟初始化模式 | 延迟初始化Bean |
初始化方法 | 初始化回调 |
销毁方法 | 销毁回调 |
除了包含关于如何建立特定bean的信息的bean定义以外,ApplicationContext
实现还容许注册(由用户)在容器外部建立的现有对象,经过getBeanFactory()
方法访问ApplicationContext
的BeanFactory
,该方法返回BeanFactory DefaultListableBeanFactory
实现。DefaultListableBeanFactory
经过registerSingleton(..)
和registerBeanDefinition(..)
方法支持这种注册,然而,典型的应用程序只使用经过常规bean定义元数据定义的bean。api
Bean元数据和手动提供的单例实例须要尽早注册,以便容器在自动装配和其余内省步骤中正确地推断它们,虽然在某种程度上支持覆盖现有的元数据和现有的单例实例,可是在运行时注册新bean(与对工厂的实时访问同时进行)并非官方支持的,而且可能会致使并发访问异常、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提供name
或id
,若是不显式提供name
或id
,容器将为该bean生成惟一的名称,可是,若是你但愿经过名称引用该bean,经过使用ref
元素或服务定位器样式查找,你必须提供一个名称,不提供名称的动机与使用内部bean和自动装配协做者有关。ui
Bean命名约定
约定是在为bean命名时使用标准Java约定做为实例字段名,也就是说,bean名称以小写字母开头,并采用驼峰大小写,此类名称的示例包括
accountManager
、accountService
、userDao
、loginController
等等。this一致地命名bean使你的配置更容易阅读和理解,另外,若是你使用Spring AOP,当你将advice应用到一组按名称关联的bean时,它会提供很大的帮助。编码
使用类路径中的组件扫描,Spring按照前面描述的规则为未命名的组件生成bean名称:本质上,取简单的类名并将其初始字符转换为小写,可是,在(不寻常的)特殊状况下,若是有多个字符,而且第一个和第二个字符都是大写的,则保留原来的大小写,这些规则与
java.beans.Introspector.decapitalize
(Spring在这里使用)定义的规则相同。
在bean定义自己中,可使用id
属性指定的最多一个名称和name
属性中任意数量的其余名称的组合,为bean提供多个名称。这些名称能够是相同bean的等价别名,在某些状况下很是有用,好比经过使用特定于该组件自己的bean名称,让应用程序中的每一个组件引用公共依赖项。code
可是,指定实际定义bean的全部别名并不老是足够的,有时须要为在其余地方定义的bean引入别名,在大型系统中,配置一般在每一个子系统之间进行划分,每一个子系统都有本身的一组对象定义,在基于XML的配置元数据中,可使用<alias/>
元素来完成此任务,下面的例子说明了如何作到这一点:
<alias name="fromName" alias="toName"/>
在这种状况下,在使用别名定义以后,名为fromName
的bean(在同一个容器中)也能够称为toName
。
例如,子系统A的配置元数据能够经过subsystemA-dataSource
的名称引用数据源,子系统B的配置元数据能够经过subsystemB-dataSource
的名称引用数据源。在组合使用这两个子系统的主应用程序时,主应用程序经过myApp-dataSource
的名称引用数据源,要使全部三个名称都引用同一个对象,能够将如下别名定义添加到配置元数据中:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/> <alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
如今,每一个组件和主应用程序均可以经过唯一的名称引用数据源,而且保证不会与任何其余定义冲突(有效地建立名称空间),可是它们引用的是同一个bean。
Java配置
若是使用Java配置,可使用
@Bean
注解提供别名,有关详细信息,请参见使用@Bean
注解。
bean定义本质上是建立一个或多个对象的配方,当被询问时,容器会查看命名bean的配方,并使用该bean定义封装的配置元数据来建立(或获取)一个实际对象。
若是使用基于XML的配置元数据,则要在<bean/>
元素的class
属性中指定实例化的对象的类型(或类),这个class
属性(在内部是BeanDefinition
实例上的一个Class
属性)一般是强制性的,你能够经过如下两种方式之一使用Class
属性:
new
操做符的Java代码。static
工厂方法的实际类,在不太常见的状况下,容器调用类上的static
工厂方法来建立bean,从static
工厂方法调用返回的对象类型能够是同一个类,也能够彻底是另外一个类。内部类的名字若是要为
static
嵌套类配置bean定义,必须使用嵌套类的二进制名称。例如,若是你在
com.example
包中有一个名为SomeThing
类,这个类有一个static
嵌套类叫作OtherThing
,bean定义上的class
属性的值是com.example.SomeThing$OtherThing
。注意,在名称中使用
$
字符将嵌套的类名与外部类名分隔开。
当你使用构造函数方法建立bean时,全部的普通类均可以被Spring使用并与Spring兼容,也就是说,正在开发的类不须要实现任何特定的接口或以特定的方式编码,只需指定bean类就足够了。可是,根据你为特定bean使用的IoC类型,你可能须要一个默认(空)构造函数。
Spring IoC容器几乎能够管理你但愿它管理的任何类,它不只限于管理真正的JavaBean,大多数Spring用户更喜欢实际的JavaBean,它只有一个默认(无参数)构造函数,以及根据容器中的属性建模的适当的setter
和getter
。你还能够在容器中包含更多非bean样式的类,例如,若是你须要使用彻底不符合JavaBean规范的遗留链接池,Spring也能够很好的管理它。
使用基于XML的配置元数据,你能够指定你的bean类以下:
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
有关向构造函数提供参数(若是须要)和在构造对象以后设置对象实例属性的机制的详细信息,请参阅注入依赖项。
在定义使用静态工厂方法建立的bean时,使用class
属性指定包含static
工厂方法的类,使用factory-method
属性指定工厂方法自己的名称。你应该可以调用这个方法(带有可选参数,如后面所述)并返回一个活动对象,随后将其视为经过构造函数建立的,这种bean定义的一个用途是在遗留代码中调用static
工厂。
下面的bean定义指定经过调用工厂方法建立bean,定义没有指定返回对象的类型(类),只指定包含工厂方法的类,在本例中,createInstance()
方法必须是一个静态方法,下面的例子展现了如何指定工厂方法:
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
下面的例子展现了一个使用前面bean定义的类:
public class ClientService { private static ClientService clientService = new ClientService(); private ClientService() {} public static ClientService createInstance() { return clientService; } }
有关向工厂方法提供(可选)参数并在对象从工厂返回后设置对象实例属性的机制的详细信息,请参阅依赖项和配置。
与经过静态工厂方法实例化相似,使用实例工厂方法实例化将从容器中调用现有bean的非静态方法来建立新bean,要使用此机制,请保留class
属性为空,并在factory-bean
属性中,在当前(或父或祖先)容器中指定bean的名称,该容器包含要调用来建立对象的实例方法,使用factory-method
属性设置工厂方法自己的名称,下面的例子展现了如何配置这样一个bean:
<!-- the factory bean, which contains a method called createInstance() --> <bean id="serviceLocator" class="examples.DefaultServiceLocator"> <!-- inject any dependencies required by this locator bean --> </bean> <!-- the bean to be created via the factory bean --> <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
下面的例子显示了相应的Java类:
public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl(); public ClientService createClientServiceInstance() { return clientService; } }
一个工厂类也能够包含多个工厂方法,以下例所示:
<bean id="serviceLocator" class="examples.DefaultServiceLocator"> <!-- inject any dependencies required by this locator bean --> </bean> <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/> <bean id="accountService" factory-bean="serviceLocator" factory-method="createAccountServiceInstance"/>
下面的例子显示了相应的Java类:
public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl(); private static AccountService accountService = new AccountServiceImpl(); public ClientService createClientServiceInstance() { return clientService; } public AccountService createAccountServiceInstance() { return accountService; } }
这种方法代表,工厂bean自己能够经过依赖项注入(DI)进行管理和配置。
在Spring文档中,“工厂bean”指的是在Spring容器中配置的bean,它经过实例或静态工厂方法建立对象,相反,FactoryBean
(注意大小写)指的是特定于spring的FactoryBean
。