码迷,mamicode.com
首页 > 编程语言 > 详细

【Spring】FactoryBean接口的实现原理(八)

时间:2021-04-15 12:36:45      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:The   tca   存在   star   code   也有   actual   nfa   引用   

一、FactoryBean与BeanFactory

  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 }

 

【Spring】FactoryBean接口的实现原理(八)

标签:The   tca   存在   star   code   也有   actual   nfa   引用   

原文地址:https://www.cnblogs.com/h--d/p/14660424.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!