天天看點

spring的BeanFactory和ApplicationContext

歡迎通路我的GitHub

這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos
  • 文中涉及的spring版本号為4.1.8.RELEASE;

BeanFactory接口

  • 在spring容器中,BeanFactory接口是IOC容器要實作的最基礎的接口,定義了管理bean的最基本的方法,例如擷取執行個體、基本的判斷等,如下圖:
spring的BeanFactory和ApplicationContext
  • BeanFactory有多個子接口來進一步擴充bean相關的功能,以下兩個與本文有直接關系,需要關注:
  • HierarchicalBeanFactory:beanFactory可以設定ParentBeanFactory,這個接口的兩個方法都是和ParentBeanFactory相關的,getParentBeanFactory方法傳回ParentBeanFactory,containsLocalBean方法是相對containsBean方法而言的,containsBean方法找不到bean的時候會通過ParentBeanFactory去找,而containsLocalBean隻在目前beanFactory找;
  • ListableBeanFactory:主要用于擷取bean相關資訊,例如擷取所有bean名稱,查找指定類型的所有bean等,如下圖:
spring的BeanFactory和ApplicationContext

ApplicationContext接口

  • 關于ApplicationContext和BeanFactory的關系,看類圖即可一目了然:
spring的BeanFactory和ApplicationContext
  • 原來ApplicationContext繼承了HierarchicalBeanFactory和ListableBeanFactory,也就是說前面看到的接口特性都被ApplicationContext繼承下來了,另外通過類圖可以發現,ApplicationContext還繼承了諸如Environment、Resource、Message、Event
  • 等相關的接口,也就是說除了bean的管理配置相關的能力,ApplicationContext還擁有了Environment(環境)、MessageSource(國際化)、ResourceLoader(資源)、ApplicationEventPublisher(應用事件)等服務相關的接口,簡單的說ApplicationContext是以bean管理為基礎的綜合能力擴充,用于滿足業務對Spring綜合能力的需要;
  • 再看看ApplicationContext源碼,除了繼承,它自身也提供了一些擴充的能力:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	//辨別目前context執行個體的id,最終會通過native方法來生成:System.identityHashCode
	String getId();

	//傳回該context所屬的應用名稱,預設為空字元串,在web應用中傳回的是servlet的contextpath 
	String getApplicationName();

	//傳回目前context的名稱
	String getDisplayName();

	//傳回context第一次被加載的時間
	long getStartupDate();

	//傳回該context的parent
	ApplicationContext getParent();

	//傳回具有自動裝配能力的beanFactory,預設傳回的就是初始化時執行個體化的beanFactory
	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
           
  • 小結:
  1. BeanFactory是基礎,BeanFactory和它的子接口定義的API滿足了spring環境中對bean管理和配置的需求;
  2. ApplicationContext是擴充,以BeanFactory為主線,通過繼承的方式綜合了環境、國際化、資源、事件等多條支線,自己又規定了一些擴充服務(如傳回context的id,應用名稱等),而所有支線都以bean服務為基礎;

實作類解析

  • 如果有個類實作了ApplicationContext接口,就必須實作上述多個接口定義的方法,這個類豈不是很複雜?我們看看AbstractApplicationContext類的源碼,這是個基礎抽象類,常用的ClassPathXmlApplicationContext、AnnotationConfigServletWebServerApplicationContext等都繼承自AbstractApplicationContext;
  • 先看看是如何實作BeanFactory接口中定義的方法的:
@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name, requiredType);
	}

	@Override
	public <T> T getBean(Class<T> requiredType) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(requiredType);
	}

	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name, args);
	}

	@Override
	public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(requiredType, args);
	}

	@Override
	public boolean containsBean(String name) {
		return getBeanFactory().containsBean(name);
	}

	@Override
	public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
		assertBeanFactoryActive();
		return getBeanFactory().isSingleton(name);
	}

	@Override
	public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
		assertBeanFactoryActive();
		return getBeanFactory().isPrototype(name);
	}

	@Override
	public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException {
		assertBeanFactoryActive();
		return getBeanFactory().isTypeMatch(name, targetType);
	}

	@Override
	public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
		assertBeanFactoryActive();
		return getBeanFactory().getType(name);
	}

	@Override
	public String[] getAliases(String name) {
		return getBeanFactory().getAliases(name);
	}
           
  • 看過上述代碼後恍然大悟,原來AbstractApplicationContext并沒有自己來完成bean的管理配置,而是全部委托給了getBeanFactory()方法傳回的這個執行個體,接口是組合,實作也是組合,這種清晰的設計是學習典範;
  • 再來看看getBeanFactory()方法,解釋究竟是誰在真正的提供bean的管理配置服務,該方法的實作在AbstractApplicationContext的子類AbstractRefreshableApplicationContext中,代碼很簡單,傳回了成員變量beanFactory:
public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}
           
  • 該成員變量在refreshBeanFactory方法中執行個體化,而refreshBeanFactory方法又是在spring容器初始化的時候調用的,是以容器初始化之後,AbstractApplicationContext就具備了bean管理配置的能力;

擴充思考

  • 看了AbstractApplicationContext類中beanFactory相關的代碼,我就猜想:**莫非Message支線也是這個套路,委托給Message服務相關的執行個體來完成?**看代碼吧:
@Override
	public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
		return getMessageSource().getMessage(code, args, defaultMessage, locale);
	}

	@Override
	public String getMessage(String code, Object args[], Locale locale) throws NoSuchMessageException {
		return getMessageSource().getMessage(code, args, locale);
	}

	@Override
	public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
		return getMessageSource().getMessage(resolvable, locale);
	}
           

歡迎關注51CTO部落格:程式員欣宸