7.3.2 bean的实例化

优质
小牛编辑
126浏览
2023-12-01

7.3.2 bean的实例化

bean的定义本质上是创建一个或多个对象的配方。当被请求时,容器在配方中查找指定名称的bean,使用bean定义中封装的配置元数据来创建(或得到)一个实际的对象。

如果使用基于XML的配置元数据,在<bean/>元素的class属性中指定被实例化对象的类型(或类)。class属性通常是强制性的,它在内部实质是BeanDefinition实例的Class属性。(例外情况,请见使用实例工厂方法实例化一节和7.7 bean定义的继承。)

您可以以两种方式使用Class属性:

  • 通常,在容器本身通过反射调用类的构造方法直接创建bean的情况下,需要指定bean的要被构建的类,一定程度上相当于Java代码中使用new操作符。
  • 在容器调用一个类的静态工厂方法创建bean这种不太常见的情况下,需要指定含有静态工厂方法的实际类。调用静态工厂方法返回的对象类型可能是同一个类,也可能是另一个类。

内部类的名称

如果要为一个静态嵌套类配置bean定义,必须使用嵌套类的二进制名称。例如,如果在com.example包中有一个叫Foo的类,同时这个类中有一个叫Bar静态嵌套类,那么bean定义中'class'属性的值将是:

com.example.Foo$Bar

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

使用构造方法实例化

当以构造方法的方式创建bean,所有普通的类对Spring而言都是可用且兼容的。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。仅指定bean的类应该就足够了。不过,取决于为具体的bean使用什么类型的IoC,可能需要一个默认(空)的构造方法。

实际上,Spring的IoC容器能管理您想让它管理的任何类,不限于管理JavaBean。大多数Spring的用户更喜欢容器中实际的JavaBean,只有一个默认(无参)构造方法和在属性之后模式化的setter和getter方法。容器中也可以有更奇特的非bean样式的类。例如,如果您需要使用一个绝对不符合JavaBean规范的遗留的连接池,Spring同样可以管理它。

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

<bean class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

关于向构造方法提供参数(如果需要)的机制以及在对象创建后设置对象实例属性的细节,请参阅依赖注入。

使用静态工厂方法实例化

当定义一个通过静态工厂方法创建的bean时,使用class属性来指定拥有该静态工厂方法的类,同时使用名为factory-method的属性指定该工厂方法的名字。要确保可以调用这个方法(可以带有可选的参数,这一点稍后再介绍),并返回一个像是通过构造方法创建的对象。这样的bean定义的一个用法是在遗留代码中调用静态工厂。

下面的bean定义指定了bean将通过调用一个工厂方法来创建。定义并不指定返回对象的类型(类),仅指定拥有工厂方法的类。在这个例子中,createInstance()方法必须是一个静态方法。

bean
    class="examples.ClientService"
    factory-method="createInstance"/>
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属性为该工厂方法的名字。

<!-- the factory bean, which contains a method called createInstance() -->
<bean class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private DefaultServiceLocator() {}

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

一个工厂类可以持有多于一个的工厂方法,如下所示:

<bean class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<bean
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>

<bean
    factory-bean="serviceLocator"
    factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();
    private static AccountService accountService = new AccountServiceImpl();

    private DefaultServiceLocator() {}

    public ClientService createClientServiceInstance() {
        return clientService;
    }

    public AccountService createAccountServiceInstance() {
        return accountService;
    }

}

这种做法表明,工厂bean本身也可以通过依赖注入(DI)来配置和管理。参阅依赖和配置的细节