spring共提供了三种实例化bean的方式:构造器实例化(全类名,反射)、工厂方法(静态工厂实例化   动态工厂实例化)和FactoryBean ,下面一一详解:

1、构造器实例化

City.java



1 package com.proc.bean;
 2 
 3 public class City {
 4 
 5     private String name;
 6     private String code;
 7     
 8     public City() {
 9     }
10 
11     public City(String name, String code) {
12         this.name = name;
13         this.code = code;
14     }
15 
16     public String getName() {
17         return name;
18     }
19 
20     public void setName(String name) {
21         this.name = name;
22     }
23 
24     public String getCode() {
25         return code;
26     }
27 
28     public void setCode(String code) {
29         this.code = code;
30     }
31 
32     @Override
33     public String toString() {
34         return "City [name=" + name + ", code=" + code + "]";
35     }
36 }



 

通过构造方式配置Bean



1 <bean id="city" class="com.proc.bean.City">
2     <constructor-arg value="北京"/>
3     <constructor-arg value="BJ"/>
4 </bean>



 

测试代码



1 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
2 City city=ctx.getBean("city", City.class);
3 System.out.println(city);



输出结果



City [name=北京, code=BJ]



 

2、静态工厂实例化

  先创建一个静态工厂StaticCityFactory



1 package com.proc.bean;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 public class StaticCityFactory {
 7     
 8     private static Map<String, City> cities;
 9     
10     static{
11         cities=new HashMap<String, City>();
12         cities.put("BJ", new City("北京", "BJ"));
13         cities.put("SH", new City("上海", "SH"));
14         cities.put("CD", new City("成都", "CD"));
15         cities.put("SZ", new City("深圳", "SZ"));
16     }
17 
18     public static City getCity(String code){
19         return cities.get(code);
20     }
21 }



 

  配置bean



1 <!-- 通过静态工厂实例化对象
2     class:静态工厂类型
3     factory-method:静态工厂静态方法名称
4     constructor-arg:为静态工厂方法指定参数
5  -->
6 <bean id="city" class="com.proc.bean.StaticCityFactory" factory-method="getCity">
7     <constructor-arg value="BJ"/>
8 </bean>



 

3、动态工厂实例化

  先创建一个实例化工厂



1 package com.proc.bean;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 public class InstanceCityFactory {
 7     
 8     private Map<String, City> cities;
 9     {
10         cities=new HashMap<String, City>();
11         cities.put("BJ", new City("北京", "BJ"));
12         cities.put("SH", new City("上海", "SH"));
13         cities.put("CD", new City("成都", "CD"));
14         cities.put("SZ", new City("深圳", "SZ"));
15     }
16     
17     public City getCity(String code){
18         return cities.get(code);
19     }
20 }



  配置



1 <!-- 配置实例化工厂 -->
2 <bean id="cityFacotry" class="com.proc.bean.InstanceCityFactory"/>
3  
4  <!-- 通过实例化工厂获取对象 -->
5 <bean id="city" factory-bean="cityFacotry" factory-method="getCity">
6     <constructor-arg value="SH"/> <!-- 配置参数 -->
7 </bean>



 

4、FactoryBean

  

   一般情况下,Spring 通过反射机制利用 <bean> 的 class 属性指定实现类实例化 Bean ,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 <bean> 中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。

  FactoryBean接口对于 Spring 框架来说占用重要的地位, Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利。从 Spring 3.0 开始, FactoryBean 开始支持泛型,即接口声明改为 FactoryBean<T> 的形式:



1 public interface FactoryBean<T> {  
2     T getObject() throws Exception;  
3     Class<?> getObjectType();  
4     boolean isSingleton();  
5 }



  在该接口中还定义了以下3 个方法:

    T getObject():返回由 FactoryBean 创建的 Bean 实例,如果 isSingleton() 返回 true ,则该实例会放到Spring 容器中单实例缓存池中;

    boolean isSingleton():返回由 FactoryBean 创建的 Bean 实例的作用域是 singleton 还是 prototype ;

    Class<T> getObjectType():返回 FactoryBean 创建的 Bean 类型。

  当配置文件中<bean> 的 class 属性配置的实现类是 FactoryBean 时,通过 getBean() 方法返回的不是FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象,相当于 FactoryBean#getObject() 代理了getBean() 方法。

 

  例:如果使用传统方式配置下面Car 的 <bean> 时, Car 的每个属性分别对应一个 <property> 元素标签。



1 public class Car {
 2     private int maxSpeed;
 3     private String brand;
 4     private double price;
 5     public int getMaxSpeed() {
 6         return this.maxSpeed;
 7     }
 8     public void setMaxSpeed(int maxSpeed) {
 9         this.maxSpeed = maxSpeed;
10     }
11     public String getBrand() {
12         return this.brand;
13     }
14     public void setBrand(String brand) {
15         this.brand = brand;
16     }
17     public double getPrice() {
18         return this.price;
19     }
20     public void setPrice(double price) {
21         this.price = price;
22     }
23 }



  如果用FactoryBean 的方式实现就灵活点,下例通过逗号分割符的方式一次性的为 Car 的所有属性指定配置值:



public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }
    public Class<Car> getObjectType() {
        return Car.class;
    }
    public boolean isSingleton() {
        return false;
    }
    public String getCarInfo() {
        return this.carInfo;
    }
    // 接受逗号分割符设置属性信息
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}



  有了这个CarFactoryBean 后,就可以在配置文件中使用下面这种自定义的配置方式配置 Car Bean 了:



1 <bean id="car" class="com.baobaotao.factorybean.CarFactoryBean">
2     <property name="carInfo" value="法拉利 ,400,2000000"/>
3 </bean>



  当调用getBean("car") 时, Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时Spring 容器就调用接口方法 CarFactoryBean#getObject() 方法返回。如果希望获取 CarFactoryBean 的实例,则需要在使用 getBean(beanName) 方法时在 beanName 前显示的加上 "&" 前缀:如 getBean("&car");