一般情况下, Spring是通过反射机制利用bean的class属性指定实现类来完成实例化bean的。在某些特定的情况下, 想做一些定制,Spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口, 用户可以通过实现该接口定制实例化bean的逻辑。
Spring从3.0开始, FactoryBean开始支持泛型, 即接口声明改为: FactoryBean<T> 的形式。
1 package org.springframework.beans.factory; 2 3 public interface FactoryBean<T> { 4 5 /** 6 * 7 * @return 返回由FactoryBean创建的bean实例, 如果isSingleton()返回true, 则该实例则会放到Spring容器单实例缓存池中 8 * @throws Exception 9 */ 10 T getObject() throws Exception; 11 12 /** 13 * 14 * @return 返回FactoryBean创建Bean的类型 15 */ 16 Class<?> getObjectType(); 17 18 /** 19 * 20 * @return 返回有FactoryBean创建的bean实例的作用域是singleten还是prototype 21 */ 22 boolean isSingleton(); 23 }
Action
创建一个pojo类<Car>。
1 /** 2 * @filename: Car.java 3 * @author: Wang Chinda 4 * @date: 2018-05-22 5 * @version: v1.0 6 * @modify_history: - 7 * 20180522 Wang Chinda create 8 * 20180522 Wang Chinda modify method() 9 */ 10 package com.itdoc.learn.source.factory; 11 12 /** 13 * @desc FactoryBean 的使用 14 * @author Wang Chinda 15 * @create 2018-05-22 16:07 16 */ 17 public class Car { 18 /** 最大速度 */ 19 private int maxSpeed; 20 /** 品牌 */ 21 private String brand; 22 /** 价钱 */ 23 private double price; 24 25 public int getMaxSpeed() { 26 return maxSpeed; 27 } 28 29 public void setMaxSpeed(int maxSpeed) { 30 this.maxSpeed = maxSpeed; 31 } 32 33 public String getBrand() { 34 return brand; 35 } 36 37 public void setBrand(String brand) { 38 this.brand = brand; 39 } 40 41 public double getPrice() { 42 return price; 43 } 44 45 public void setPrice(double price) { 46 this.price = price; 47 } 48 49 @Override 50 public String toString() { 51 return "Car{" + 52 "maxSpeed=" + maxSpeed + 53 ", brand='" + brand + '\'' + 54 ", price=" + price + 55 '}'; 56 } 57 }
创建一个定制实例化bean逻辑的类<CarFactoryBean>:
1 /** 2 * @filename: CarFactoryBean.java 3 * @author: Wang Chinda 4 * @date: 2018-05-22 5 * @version: v1.0 6 * @modify_history: - 7 * 20180522 Wang Chinda create 8 * 20180522 Wang Chinda modify method() 9 */ 10 package com.itdoc.learn.source.factory; 11 12 import org.springframework.beans.factory.FactoryBean; 13 14 /** 15 * @desc FactoryBean测试的工厂类 16 * @author Wang Chinda 17 * @create 2018-05-22 16:17 18 */ 19 public class CarFactoryBean implements FactoryBean<Car> { 20 21 /** 车的详细信息 */ 22 private String carInfo; 23 24 @Override 25 public Car getObject() throws Exception { 26 Car car = new Car(); 27 String[] infos = carInfo.split(","); 28 car.setBrand(infos[0].trim()); 29 car.setMaxSpeed(Integer.valueOf(infos[1].trim())); 30 car.setPrice(Double.valueOf(infos[2].trim())); 31 return car; 32 } 33 34 @Override 35 public Class<Car> getObjectType() { 36 return Car.class; 37 } 38 39 @Override 40 public boolean isSingleton() { 41 return false; 42 } 43 44 public String getCarInfo() { 45 return carInfo; 46 } 47 48 public void setCarInfo(String carInfo) { 49 this.carInfo = carInfo; 50 } 51 }
配置xml<car-factory-bean.xml>:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 6 7 <bean id="car" class="com.itdoc.learn.source.factory.CarFactoryBean"> 8 <property name="carInfo" value="超级跑车, 400, 300000000"></property> 9 </bean> 10 11 </beans>
测试<Car>:
1 /** 2 * @filename: CarClient.java 3 * @author: Wang Chinda 4 * @date: 2018-05-22 5 * @version: v1.0 6 * @modify_history: - 7 * 20180522 Wang Chinda create 8 * 20180522 Wang Chinda modify method() 9 */ 10 package com.itdoc.learn.source.factory; 11 12 import org.springframework.context.ApplicationContext; 13 import org.springframework.context.support.ClassPathXmlApplicationContext; 14 15 /** 16 * @desc FactoryBean使用测试客户端入口 17 * @author Wang Chinda 18 * @create 2018-05-22 16:27 19 */ 20 public class CarClient { 21 public static void main(String[] args) { 22 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/car-factory-bean.xml"); 23 Car car = (Car) applicationContext.getBean("car"); 24 System.out.println(car); 25 } 26 }
控制台打印:
流程分析:
当配置文件中<bean>的class属性配置类的实现类是FactoryBean时, 通过getBean返回的不是FactoryBean本身, 而是FactoryBean#getObject()方法返回的对象, 相当于FactoryBean#getObject()代理了getBean()方法。
从缓存中或者singletonFactories中的ObjectFactory中获取共享实例。
Object sharedInstance = getSingleton(beanName);
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 获取对应实例。
强制将共享实例转化成FactoryBean。FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
object = getObjectFromFactoryBean(factory, beanName, !synthetic); 在FactoryBean中获取bean实例。
doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
调用getObject()方法,object = factory.getObject();
返回实例bean。
GitHub源码: https://github.com/wcd19901010/spring-01