Spring 源码学习(2) —— FactoryBean 的使用

一般情况下, 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

猜你喜欢

转载自www.cnblogs.com/goodcheap/p/9073287.html
今日推荐