天天看點

Spring源碼解析 - FactoryBean&&BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean

  1. 加載配置檔案
  2. 解析
  3. 封裝成 BeanDefinition 對象
  4. 執行個體化
  5. 完整對象
  6. 使用

讀取各種形式比如 json、注解、xml 的配置,就通過BeanDefinitionReader 讀取。并非直接反射BeanDefinition注入值得到對象,否則 Spring 毫無意義。

BeanFactory

等同于容器。

何時使用FactoryBean?

FactoryBean是一個工廠Bean,可生成某一個類型的Bean執行個體。

最大作用:讓我們能夠自定義Bean的建立過程。

而在BeanFactory中可建立和管理Spring容器中的Bean,它對Bean的建立有一個統一的流程。

1 FactoryBean

定義

  • 泛型接口
Spring源碼解析 - FactoryBean&&BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean

API

  • 傳回Bean對象執行個體
Spring源碼解析 - FactoryBean&&BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean
  • Bean類型
Spring源碼解析 - FactoryBean&&BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean
  • 是否單例。true是單例,false是非單例 。在Spring5.x利用Java8新特性變成default方法,傳回true
Spring源碼解析 - FactoryBean&&BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean

2 使用FactoryBean

//FactoryBean接口實作類
@Component
public class FactoryBeanLearn implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        // 自己new,這裡就可以控制Bean的建立過程
        return new FactoryBeanServiceImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return FactoryBeanService.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

接口
public interface FactoryBeanService {

    /**
     * 測試FactoryBean
     */
    void testFactoryBean();
}

//實作類
public class FactoryBeanServiceImpl implements FactoryBeanService {

    @Override
    public void testFactoryBean() {
        System.out.println("我是FactoryBean的一個測試類。。。。");
    }
}

測試類
@Test
public void test() {
        ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:com/javaedge/applicationContext.xml");
        FactoryBeanService beanService = cac.getBean(FactoryBeanService.class);
        beanService.testFactoryBean();
    }      

從Spring容器中擷取了FactoryBeanService類型的Bean。那麼這個擷取Bean的過程Spring是怎麼處理的呢?它是怎麼從FactoryBean中擷取我們自己建立的Bean執行個體的呢?

先從getBean這個方法看起,在Spring的AbstractApplicationContext中有很多重載的getBean方法,這裡調用根據Type(Class類型)來擷取的Bean資訊。我們傳入type是FactoryBeanService類型。

getBean

AbstractApplicationContext#getBean(java.lang.Class)

Spring源碼解析 - FactoryBean&amp;&amp;BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean
Spring源碼解析 - FactoryBean&amp;&amp;BeanFactory(上)BeanFactory何時使用FactoryBean?1 FactoryBean2 使用FactoryBeangetBean

resolveBean

@Nullable
    private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
        // 解析Bean
        NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        }
        // 如果目前Spring容器中沒擷取到對應Bean資訊,則從父容器擷取
        BeanFactory parent = getParentBeanFactory();
        if (parent instanceof DefaultListableBeanFactory) {
            return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
        }
        else if (parent != null) {
            ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
            if (args != null) {
                return parentProvider.getObject(args);
            }
            else {
                return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
            }
        }
        return null;
    }