日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
面試官:BeanFactory和FactoryBean有哪些區(qū)別?

[[398320]]

區(qū)別

說實(shí)話,他倆除了名字比較像以外,好像沒有其他共同點(diǎn)了。

創(chuàng)新互聯(lián)公司提供高防主機(jī)、云服務(wù)器、香港服務(wù)器、雙線服務(wù)器托管等

「BeanFactory和FactoryBean有哪些區(qū)別?」

  1. BeanFactory是一個(gè)最基礎(chǔ)的IOC容器,提供了依賴查找,依賴注入等基礎(chǔ)的功能
  2. FactoryBean是創(chuàng)建Bean的一種方式,幫助實(shí)現(xiàn)復(fù)雜Bean的創(chuàng)建

和BeanFactory相關(guān)的還有一個(gè)高頻的面試題

「ApplicationContext和BeanFactory有哪些區(qū)別?」

  1. BeanFactory是一個(gè)最基礎(chǔ)的IOC容器,提供了依賴查找,依賴注入等基礎(chǔ)的功能
  2. ApplicationContext繼承了BeanFactory,在BeanFactory的基礎(chǔ)上增加了企業(yè)級的功能,如AOP,資源管理(Resources)事件(Event),國際化(i18n),Environment抽象等

創(chuàng)建Bean的方式

常見的創(chuàng)建Bean的方式有如下四種

  1. 通過構(gòu)造器
  2. 通過靜態(tài)工廠方法
  3. 通過Bean工廠方法
  4. 通過FactoryBean
 
 
 
 
  1. @Data 
  2. @ToString 
  3. public class User { 
  4.  
  5.  private Long id; 
  6.  private String name; 
  7.  
  8.  public static User createUser() { 
  9.   User user = new User(); 
  10.   user.setId(1L); 
  11.   user.setName("li"); 
  12.   return user; 
  13.  } 
 
 
 
 
  1. public class UserFactory { 
  2.  
  3.  public User createUser() { 
  4.   return User.createUser(); 
  5.  } 
 
 
 
 
  1. public class UserFactoryBean implements FactoryBean { 
  2.  
  3.  @Override 
  4.  public Object getObject() throws Exception { 
  5.   return User.createUser(); 
  6.  } 
  7.  
  8.  @Override 
  9.  public Class getObjectType() { 
  10.   return User.class; 
  11.  } 
 
 
 
 
  1.  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  3.     xsi:schemaLocation="http://www.springframework.org/schema/beans 
  4.         https://www.springframework.org/schema/beans/spring-beans.xsd"> 
  5.  
  6.   
  7.   
  8.    
  9.          
  10.   
  11.  
  12.   
  13.  
  14.     factory-method="createUser"/> 
  15.  
  16.   
  17.  
  18.   
  19.   
  20.  
  21.   
  22.   
 
 
 
 
  1. public class BeanInstantiationDemo { 
  2.  
  3.  public static void main(String[] args) { 
  4.   BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/bean-instantiation-context.xml"); 
  5.   User user1 = beanFactory.getBean("user-by-constructor", User.class); 
  6.   User user2 = beanFactory.getBean("user-by-static-method", User.class); 
  7.   User user3 = beanFactory.getBean("user-by-factory", User.class); 
  8.   User user4 = beanFactory.getBean("user-by-factory-bean", User.class); 
  9.  } 

實(shí)現(xiàn)原理

在分析源碼之前,我們先明確2個(gè)概念

「factoryBean是我們配置到容器中的實(shí)現(xiàn)FactoryBean接口的Bean,而subBean是用FactoryBean創(chuàng)建出來的Bean」

在Spring容器啟動的過程中,會實(shí)例化非延遲的單例Bean,即調(diào)用如下方法 DefaultListableBeanFactory#preInstantiateSingletons

調(diào)用FactoryBean#getObject的鏈路如下圖

通過分析DefaultListableBeanFactory#preInstantiateSingletons方法和FactoryBean#getObject的調(diào)用鏈路可以分析得到

  1. 單例的factoryBean對象本身會在spring容器啟動時(shí)主動初始化。而subBean的初始化則是在第一次從緩存中獲取factoryBean并且不為空才會觸發(fā)
  2. 如果factoryBean對象實(shí)現(xiàn)的接口是SmartFactoryBean且isEagerInit方法返回true,那么subBean對象也會在spring容器啟動的時(shí)候主動初始化
  3. 如果bean注冊的時(shí)候,beanName對應(yīng)的bean實(shí)例是一個(gè)factoryBean,那么我們通過getBean(beanName)獲取到的對象將會是subBean對象;如果要獲取工廠對象factoryBean,需要使用getBean("&" + beanName)
  4. 單例的subBean也會緩存在spring容器中,具體的容器是FactoryBeanRegistrySupport#factoryBeanObjectCache,一個(gè)Map

「建議大家看一下DefaultListableBeanFactory#preInstantiateSingletons方法和FactoryBean#getObject方法的調(diào)用鏈路,就能理解上面我說的流程了,我就不貼太多源碼了」

應(yīng)用

目前我只在Dubbbo源碼中看到了FactoryBean的應(yīng)用

「服務(wù)導(dǎo)出:在Dubbo中,服務(wù)提供者會被包裝成ServiceBean對象,當(dāng)監(jiān)聽到ContextRefreshedEvent事件時(shí)開始服務(wù)導(dǎo)出」

「服務(wù)調(diào)用:服務(wù)調(diào)用方會被包裝成ReferenceBean對象,ReferenceBean實(shí)現(xiàn)了FactoryBean接口和InitializingBean接口,創(chuàng)建subBean的邏輯在ReferenceBean#getObject方法中」

「Dubbo服務(wù)引入的時(shí)機(jī)有如下2種?!?/p>

  1. 餓漢式:init=true,在Bean生命周期的初始化階段會調(diào)用InitializingBean#afterPropertiesSet方法,而這個(gè)方法會調(diào)用ReferenceBean#getObject方法,完成subBean的創(chuàng)建,即ReferenceBean實(shí)例化時(shí)完成服務(wù)引入
  2. 懶漢式:init=false,在ReferenceBean對應(yīng)的服務(wù)被注入到其他類中時(shí),此時(shí)會調(diào)用AbstractApplicationContext#getBean,獲取ReferenceBean對象,因?yàn)镽eferenceBean實(shí)現(xiàn)了FactoryBean接口,所以會調(diào)用ReferenceBean#getObject方法,完成subBean的創(chuàng)建,即完成服務(wù)引入
 
 
 
 
  1. public class ReferenceBean extends ReferenceConfig implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean { 
  2.  
  3.     @Override 
  4.     public Object getObject() { 
  5.         return get(); 
  6.     } 
  7.  
  8.     @Override 
  9.     @SuppressWarnings({"unchecked"}) 
  10.     public void afterPropertiesSet() throws Exception { 
  11.  
  12.         // 省略部分代碼 
  13.  
  14.         if (shouldInit()) { 
  15.             getObject(); 
  16.         } 
  17.     } 
  18.      

本文轉(zhuǎn)載自微信公眾號「Java識堂」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Java識堂公眾號。


本文題目:面試官:BeanFactory和FactoryBean有哪些區(qū)別?
網(wǎng)頁URL:http://www.dlmjj.cn/article/dpedhee.html