Bean 概述
Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的(例如,以XML 定义的形式 )。
在容器本身内,这些bean定义表示为BeanDefinition 对象,其中包含以下元数据(以及其他信息):
-
包限定的类名:通常是正在定义的bean的实际实现类。
-
Bean行为配置元素,说明bean在容器中的行为方式(范围,生命周期回调等)。
-
引用bean执行其工作所需的其他bean。这些引用也称为协作者或依赖项。
-
要在新创建的对象中设置的其他配置设置 - 例如,池的大小限制或在管理连接池的Bean中使用的连接数。
此元数据转换为组成每个bean定义的一组属性。下表描述了这些属性:
表1. bean定义
属性值 | 解释 |
---|---|
Class | Instantiating Beans(实例化的Bean) |
Name | Naming Beans(Bean的名称) |
Scope | Bean Scopes(Bean的作用范围) |
Constructor arguments | Dependency Injection(构造参数,依赖注入) |
Properties | Dependency Injection(属性值,依赖注入) |
Autowiring mode(自动装配模式) | Autowiring Collaborators(自动化协作者) |
Lazy initialization mode | Lazy-initialized Beans(懒惰初始化的Bean) |
Initialization method | Initialization Callbacks(初始化回调) |
Destruction method | Destruction Callbacks(销毁回调) |
除了包含有关如何创建特定bean的信息的bean定义之外,这些ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过方法访问ApplicationContext的BeanFactory来完成的getBeanFactory(),该方法返回BeanFactory DefaultListableBeanFactory实现。DefaultListableBeanFactory 通过registerSingleton(…)和 registerBeanDefinition(…)方法支持此注册。但是,典型应用程序仅适用于通过常规bean定义元数据定义的bean。
需要尽早注册Bean元数据和手动提供的单例实例,以便容器在自动装配和其他内省步骤期间正确推理它们。虽然在某种程度上支持覆盖现有元数据和现有单例实例,但是在运行时注册新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类型。请注意,id容器仍然强制执行bean 唯一性,但不再是XML解析器。
您不需要提供一个name或id一个bean。如果您不提供 name或id显式提供,则容器会为该bean生成唯一的名称。但是,如果要通过名称引用该bean,通过使用ref元素或 Service Locator样式查找,则必须提供名称。不提供名称的动机与使用内部bean和自动装配协作者有关。
Bean命名约定
惯例是在命名bean时使用标准Java约定作为实例字段名称。也就是说,bean名称以小写字母开头,并从那里开始驼峰。这样的名字的例子包括accountManager, accountService,userDao,loginController,等等。
命名bean始终使您的配置更易于阅读和理解。此外,如果您使用Spring AOP,那么在将建议应用于与名称相关的一组bean时,它会有很大帮助。
注意:通过类路径中的组件扫描,Spring按照前面描述的规则为未命名的组件生成bean名称:基本上,采用简单的类名并将其初始字符转换为小写。但是,在(不常见的)特殊情况下,当有多个字符并且第一个和第二个字符都是大写字母时,原始外壳将被保留。这些规则与java.beans.Introspector.decapitalize(Spring在此处使用)定义的规则相同。
给Bean定义别名Bean
在bean定义本身中,您可以为bean提供多个名称,方法是使用id属性指定的最多一个名称和属性中的任意数量的其他名称name。这些名称可以是同一个bean的等效别名,对某些情况很有用,例如让应用程序中的每个组件通过使用特定于该组件本身的bean名称来引用公共依赖项。
但是,指定实际定义bean的所有别名并不总是足够的。有时需要为其他地方定义的bean引入别名。在大型系统中通常就是这种情况,其中配置在每个子系统之间分配,每个子系统具有其自己的一组对象定义。在基于XML的配置元数据中,您可以使用该元素来完成此任务。以下示例显示了如何执行此操作:
<alias name="fromName" alias="toName"/>
在这种情况下,fromName在使用此别名定义之后,命名的bean(在同一容器中)也可以称为toName。
例如,子系统A的配置元数据可以通过名称引用DataSource subsystemA-dataSource。子系统B的配置元数据可以通过名称引用DataSource subsystemB-dataSource。在编写使用这两个子系统的主应用程序时,主应用程序通过名称引用DataSource myApp-dataSource。要使所有三个名称引用同一对象,可以将以下别名定义添加到配置元数据中:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
现在,每个组件和主应用程序都可以通过一个唯一的名称引用dataSource,并保证不与任何其他定义冲突(有效地创建命名空间),但它们引用相同的bean。
Java的配置
如果使用Javaconfiguration,则@Bean可以使用注解来提供别名。有关详细信息,请参阅使用@Bean注解。
1.3.2 实例化Bean
bean定义本质上是用于创建一个或多个对象的配置。容器在被询问时查看命名bean的配置,并使用由该bean定义封装的配置元数据来创建(或获取)实际对象。
如果使用基于XML的配置元数据,则指定要在元素的class属性中实例化的对象的类型(或类)。此 class属性(在内部,是 实例Class上的属性BeanDefinition)通常是必需的。(有关例外,请参阅 使用实例工厂方法和Bean定义继承进行实例化。)您可以通过以下Class两种方式之一使用该属性:
-
通常,在容器本身通过反向调用其构造函数直接创建bean的情况下指定要构造的bean类,稍微等同于使用new运算符的Java代码。
-
要指定包含static为创建对象而调用的工厂方法的实际类,在不常见的情况下,容器static在类上调用 工厂方法来创建bean。从调用static工厂方法返回的对象类型可以完全是同一个类或另一个类。
内部类名
如果要为static嵌套类配置bean定义,则必须使用嵌套类的二进制名称。例如,如果你有一个SomeThing在com.example包中调用的类,并且这个 SomeThing类有一个static被调用的嵌套类OtherThing,那么class bean定义中的属性值就是com.example.SomeThing$OtherThing。
请注意,使用$名称中的字符将嵌套类名与外部类名分开。
使用构造函数实例化
当您通过构造方法创建bean时,所有普通类都可以使用并与Spring兼容。也就是说,正在开发的类不需要实现任何特定接口或以特定方式编码。简单地指定bean类就足够了。但是,根据您为该特定bean使用的IoC类型,您可能需要一个默认(空)构造函数。
Spring IoC容器几乎可以管理您希望它管理的任何类。它不仅限于管理真正的JavaBeans。大多数Spring用户更喜欢实际的JavaBeans,只有一个默认(无参数)构造函数,并且在容器中的属性之后建模了适当的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;
}
}
这种方法表明可以通过依赖注入(DI)来管理和配置工厂bean本身。请参阅详细信息中的依赖关系和配置。
在Spring文档中,“factory bean”是指在Spring容器中配置并通过实例或 静态工厂方法创建对象的bean 。相反, FactoryBean(注意大写)指的是特定于Spring的 FactoryBean。