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");