zoukankan      html  css  js  c++  java
  • 简单分析FactoryBean

    1. 什么是FactoryBean

    FactoryBean本质上是一种Bean,只是它可以产生其他的Bean,比较特殊。在上下文getBean的时候,如果传入FactoryBean的名称,得到的是FactoryBean生产的产品,而不是FactoryBean。如果要获得FactoryBean自身,那么传入的FactoryBean名称前面要加上&字符。

    2. 一个小例子

     1 package com.khlin.my.test;
     2 
     3 import org.springframework.beans.factory.FactoryBean;
     4 import java.util.Date;
     5 
     6 public class DefaultFactoryBean implements FactoryBean<Date> {
     7     public Date getObject() throws Exception {
     8         return new Date();
     9     }
    10 
    11     public Class<?> getObjectType() {
    12         return Date.class;
    13     }
    14 
    15     public boolean isSingleton() {
    16         return true;
    17     }
    18 }
    <bean id="defaultFactoryBean" class="com.khlin.my.test.DefaultFactoryBean"/>

    再来个启动类

     1 package com.khlin.my.test;
     2 
     3 import org.springframework.beans.factory.FactoryBean;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.context.support.ClassPathXmlApplicationContext;
     6 
     7 import java.util.Date;
     8 
     9 public class FactoryBeanTest {
    10 
    11     public static void main(String[] args) {
    12         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    13         Date date = (Date) applicationContext.getBean("defaultFactoryBean");
    14         System.out.println(date);
    15         DefaultFactoryBean factoryBean = (DefaultFactoryBean) applicationContext.getBean("&defaultFactoryBean");
    16     }
    17 }

    可以看到,如果要获得产品,直接使用FactoryBean的名称。如果要获得工厂,则要在前面加上&

    3. 原理分析

    在getBean方法里,层层调用,到了AbstractBeanFactory的getObjectForBeanInstance方法,无论是获取产品还是工厂,都是先取出工厂类的Bean。

    然后对其进行类型判断。

    3.1 如果是FactoryBean并且名称不是以&开头,说明要取出产品。先是从缓存里取出产品,如果产品不存在,从工厂类中取出。

    对于单例的产品,会存储在FactoryBeanRegistrySupport的factoryBeanObjectCache里。这是一个Map,由工厂名映射到产品。

    第一次获取,肯定是为空。那么就会调用getObjectFromFactoryBean方法。在这个方法里,会先调用工厂的getObject()方法,最后放入缓存中。这样后面取产品,就可以从缓存中取出,实现了单例的语义。

    要注意的是,虽然产品是通过getObject()直接得到的,不是Spring Bean,但中间还是用BeanPostProcessor参与了其生命周期。

    最终会进入到AbstractAutowireCapableBeanFactory类。这里只调用了After的方法,没有调用Before.

    对于多例,getObjectForBeanInstance方法里,从缓存里取不出产品,同样调用getObjectFromFactoryBean。

    不同的是这次走入另一条分支。仍是调用getObject生产产品,再用BeanPostProcessors后处理,不过这次没有将其放入缓存。这也符合多例的语义,每次获得的都是新的对象。

    3.2 如果是FactoryBean但不是以&开头,只能走到最后一个分支,直接取出FactoryBean对象。

    重温上面的代码图,即走入最后一个分支,return beanInstance.

    4. 总结

    单例的产品会放在缓存里,键为工厂名,值为产品。

    多例的产品不会放在缓存。

    创建产品是直接调用工厂的getObject方法,因此产品没有Spring Bean的生命周期。

    每次创建完一个产品,会调用所有注册的BeanPostProcessors的postProcessAfterInitialization方法,参与到产品初始化的生命周期。

  • 相关阅读:
    Windows python 鼠标键盘监控及控制
    python 执行adb shell 命令
    python Windows提示框
    判断function属于函数或方法
    生成不同时间下的LOG
    pyqt5 QCalendar类中常用的方法
    python字符串大小写转换
    configparser 模块的基本方法
    QGridLayout类中常用的方法
    Day049--jQuery的文档操作和事件介绍
  • 原文地址:https://www.cnblogs.com/kingsleylam/p/11293810.html
Copyright © 2011-2022 走看看