一、FactoryBean与BeanFactory
-
BeanFactory是一个Bean工厂,在一定程度上我们可以简单理解为它就是我们平常所说的Spring容器(注意这里说的是简单理解为容器),它完成了Bean的创建、自动装配等过程,存储了创建完成的单例Bean。
-
FactoryBean通过名字看,我们可以猜出它是Bean,但它是一个特殊的Bean,FactoryBean的特殊之处在于它可以向容器中注册两个Bean,一个是它本身,一个是FactoryBean.getObject()方法返回值所代表的Bean。
二、FactoryBean的使用
1、普通对象Person
1 public class Person { 2 3 private String name; 4 5 private String sex; 6 7 public Person() { 8 System.out.println("Person() Construct Method"); 9 } 10 11 public String getName() { 12 return name; 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 19 public String getSex() { 20 return sex; 21 } 22 23 public void setSex(String sex) { 24 this.sex = sex; 25 } 26 27 @Override 28 public String toString() { 29 return "Person{" + 30 "name='" + name + '\'' + 31 ", sex='" + sex + '\'' + 32 '}'; 33 } 34 }
2、实现FactoryBean接口的实例 PersonIFactoryBean
1 public class PersonFactoryBean implements FactoryBean<Person> { 2 3 private String name; 4 5 private String sex; 6 7 public String getName() { 8 return name; 9 } 10 11 public PersonFactoryBean() { 12 System.out.println("PersonFactoryBean() Construct Method"); 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 19 public String getSex() { 20 return sex; 21 } 22 23 public void setSex(String sex) { 24 this.sex = sex; 25 } 26 27 @Override 28 public String toString() { 29 return "PersonFactoryBean{" + 30 "name='" + name + '\'' + 31 ", sex='" + sex + '\'' + 32 '}'; 33 } 34 35 @Override 36 public Person getObject() throws Exception { 37 Person person = new Person(); 38 person.setName("李四"); 39 person.setSex("男"); 40 return person; 41 } 42 43 @Override 44 public Class<?> getObjectType() { 45 return Person.class; 46 } 47 }
3、把 PersonIFactoryBean 注入到Spring容器中
1 @Configuration 2 public class MainConfig { 3 4 @Bean 5 public PersonFactoryBean personFactoryBean() { 6 PersonFactoryBean person = new PersonFactoryBean(); 7 person.setName("张三"); 8 person.setSex("女"); 9 return person; 10 } 11 12 }
4、启动类
1 public class MainStarter { 2 3 public static void main(String[] args) { 4 5 // 注解配置引用上下文 6 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); 7 8 // 测试实现FactoryBean接口的PersonIFactoryBean的用法 9 // 通过普通beanName 获取的是Person对象,调用FactoryBean接口中的getObject()方法获取对象 10 // 多次获取不会重复调用getObject()方法获取对象,会从容器中的缓存中去 11 Person person1 = (Person) context.getBean("personFactoryBean"); 12 System.out.println(person1); 13 Person person2 = (Person) context.getBean("personFactoryBean"); 14 System.out.println(person2); 15 16 // 通过& + beanName,获取的是PersonEFactoryBean对象 17 PersonFactoryBean personFactoryBean = (PersonFactoryBean) context.getBean("&personFactoryBean"); 18 System.out.println(personFactoryBean); 19 20 context.close(); 21 } 22 }
5、输出结果如下:
1 PersonFactoryBean() Construct Method 2 Person() Construct Method 3 Person{name='李四', sex='男'} 4 Person{name='李四', sex='男'} 5 PersonFactoryBean{name='张三', sex='女'}
可以看到通过beanName获取的是 getObject() 方法返回的对象,且只运行了一次
要获取实现FactoryBean接口的对象,需要在beanName前面加上 “&”
6、总结
- 在Spring容器中,获取实现FactoryBean接口的Bean时,
context.getBean("personFactoryBean"); ==> Spring会通过FactoryBean接口的getObject()方法,返回一个实例Person
- 想获取PersonIFactoryBean类对象原始实例,需要在bean的名字前面加&,如下:
context.getBean("&personFactoryBean"); ==> Spring会通过FactoryBean接口的getObject()方法,返回一个实例Person
三、FactoryBean的原理
1、FactoryBean接口内容如下:
1 public interface FactoryBean<T> { 2 3 4 String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; 5 6 // 获取对象 7 @Nullable 8 T getObject() throws Exception; 9 10 // 获取对象类型 11 @Nullable 12 Class<?> getObjectType(); 13 14 // 是否是单例 15 default boolean isSingleton() { 16 return true; 17 } 18 19 }
2、在Spring容器中,获取&personIFactoryBean 原始类时
context.getBean()->doGetBean()->getObjectForBeanInstance()
getObjectForBeanInstance() 这个方法会判断是不是普通类,还是实现FactoryBean接口的类对象,普通类对象直接返回,实现FactoryBean接口的类继续调用下面的方法
这个方法会判断bean名称,如果是以“&”开头的FromFactory接口类的bean,则直接返回
1 protected Object getObjectForBeanInstance( 2 Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { 3 4 // Don't let calling code try to dereference the factory if the bean isn't a factory. 5 // 如果 name 以 & 开头,则直接返回 6 if (BeanFactoryUtils.isFactoryDereference(name)) { 7 if (beanInstance instanceof NullBean) { 8 return beanInstance; 9 } 10 if (!(beanInstance instanceof FactoryBean)) { 11 throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); 12 } 13 if (mbd != null) { 14 mbd.isFactoryBean = true; 15 } 16 return beanInstance; 17 } 18 19 // Now we have the bean instance, which may be a normal bean or a FactoryBean. 20 // If it's a FactoryBean, we use it to create a bean instance, unless the 21 // caller actually wants a reference to the factory. 22 /** 23 * 如果上面的判断通过了,表明 beanInstance 可能是一个普通的 bean,也可能是一个 24 * FactoryBean。如果是一个普通的 bean,这里直接返回 beanInstance 即可。如果是 25 * FactoryBean,则要调用工厂方法生成一个 bean 实例。 26 */ 27 // 普通类直接返回 28 if (!(beanInstance instanceof FactoryBean)) { 29 return beanInstance; 30 } 31 32 Object object = null; 33 if (mbd != null) { 34 mbd.isFactoryBean = true; 35 } 36 else { 37 /** 38 * 如果 mbd 为空,则从缓存中加载 bean。FactoryBean 生成的单例 bean 会被缓存 39 * 在 factoryBeanObjectCache 集合中,不用每次都创建 40 */ 41 object = getCachedObjectForFactoryBean(beanName); 42 } 43 if (object == null) { 44 // Return bean instance from factory. 45 // 经过前面的判断,到这里可以保证 beanInstance 是 FactoryBean 类型的,所以可以进行类型转换 46 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 47 // Caches object obtained from FactoryBean if it is a singleton. 48 // 如果 mbd 为空,则判断是否存在名字为 beanName 的 BeanDefinition 49 if (mbd == null && containsBeanDefinition(beanName)) { 50 mbd = getMergedLocalBeanDefinition(beanName); 51 } 52 // synthetic 字面意思是"合成的"。通过全局查找,我发现在 AOP 相关的类中会将该属性设为 true。 53 // 通过观察getObjectFromFactoryBean()方法,第三个参数是shouldPostProcess,是否需要后置处理(即经过后置处理器处理) 54 // synthetic 如果为false,则后续实例需要经过后置处理器处理,反之则否 55 boolean synthetic = (mbd != null && mbd.isSynthetic()); 56 // 调用 getObjectFromFactoryBean 方法继续获取实例 57 // 从FactoryBean接口实现类的getObject()方法去获取对象 58 object = getObjectFromFactoryBean(factory, beanName, !synthetic); 59 } 60 return object; 61 }
3、而在普通beanName获取对象是
context.getBean()->doGetBean()->getObjectForBeanInstance()->getObjectFromFactoryBean()
getObjectFromFactoryBean() 调用 doGetObjectFromFactoryBean()
1 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { 2 /** 3 * FactoryBean 也有单例和非单例之分,针对不同类型的 FactoryBean,这里有两种处理方式: 4 * 1. 单例 FactoryBean 生成的 bean 实例也认为是单例类型。需放入缓存中,供后续重复使用 5 * 2. 非单例 FactoryBean 生成的 bean 实例则不会被放入缓存中,每次都会创建新的实例 6 **/ 7 if (factory.isSingleton() && containsSingleton(beanName)) { 8 synchronized (getSingletonMutex()) { 9 // 从缓存中取 bean 实例,避免多次创建 bean 实例 10 Object object = this.factoryBeanObjectCache.get(beanName); 11 if (object == null) { 12 // 调用实现FactoryBean接口对象的getObject()方法逻辑 13 object = doGetObjectFromFactoryBean(factory, beanName); 14 // Only post-process and store if not put there already during getObject() call above 15 // (e.g. because of circular reference processing triggered by custom getBean calls) 16 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); 17 if (alreadyThere != null) { 18 object = alreadyThere; 19 } 20 else { 21 // shouldPostProcess 是否需要后置处理标识 22 if (shouldPostProcess) { 23 // 判断当地的bean是否正在创建 24 if (isSingletonCurrentlyInCreation(beanName)) { 25 // Temporarily return non-post-processed object, not storing it yet.. 26 return object; 27 } 28 // 添加正在创建对象标识 29 beforeSingletonCreation(beanName); 30 try { 31 // bean后置处理器调用,处理实现FactoryBean接口的bean 32 object = postProcessObjectFromFactoryBean(object, beanName); 33 } 34 catch (Throwable ex) { 35 throw new BeanCreationException(beanName, 36 "Post-processing of FactoryBean's singleton object failed", ex); 37 } 38 finally { 39 afterSingletonCreation(beanName); 40 } 41 } 42 // 这里的 beanName 对应于 FactoryBean 的实现类, 43 // FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中 44 if (containsSingleton(beanName)) { 45 // 这里的 beanName 对应于 FactoryBean 的实现类, 46 // FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中 47 this.factoryBeanObjectCache.put(beanName, object); 48 } 49 } 50 } 51 return object; 52 } 53 } 54 else { 55 Object object = doGetObjectFromFactoryBean(factory, beanName); 56 if (shouldPostProcess) { 57 try { 58 object = postProcessObjectFromFactoryBean(object, beanName); 59 } 60 catch (Throwable ex) { 61 throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); 62 } 63 } 64 return object; 65 } 66 }
4、 doGetObjectFromFactoryBean() 方法,调用了 factory.getObject(),即调用实现FactoryBean接口的对象的getObject()获取对象
1 private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) 2 throws BeanCreationException { 3 4 Object object; 5 try { 6 if (System.getSecurityManager() != null) { 7 AccessControlContext acc = getAccessControlContext(); 8 try { 9 object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc); 10 } 11 catch (PrivilegedActionException pae) { 12 throw pae.getException(); 13 } 14 } 15 else { 16 // 调用实现FactoryBean接口对象的getObject()方法,获取对象 17 object = factory.getObject(); 18 } 19 } 20 catch (FactoryBeanNotInitializedException ex) { 21 throw new BeanCurrentlyInCreationException(beanName, ex.toString()); 22 } 23 catch (Throwable ex) { 24 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); 25 } 26 27 // Do not accept a null value for a FactoryBean that's not fully 28 // initialized yet: Many FactoryBeans just return null then. 29 // 如果没有获取到,返回一个NullBean 空bean给外面 30 if (object == null) { 31 if (isSingletonCurrentlyInCreation(beanName)) { 32 throw new BeanCurrentlyInCreationException( 33 beanName, "FactoryBean which is currently in creation returned null from getObject"); 34 } 35 object = new NullBean(); 36 } 37 return object; 38 }