一般情况下, 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{ 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还是prototype21 */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 Chinda15 * @create 2018-05-22 16:0716 */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 @Override50 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 Chinda17 * @create 2018-05-22 16:1718 */19 public class CarFactoryBean implements FactoryBean{20 21 /** 车的详细信息 */22 private String carInfo;23 24 @Override25 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 @Override35 public Class getObjectType() {36 return Car.class;37 }38 39 @Override40 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 25 6 7 8 10 119
测试<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 Chinda18 * @create 2018-05-22 16:2719 */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源码: