Spring核心系列之ApplicationContext

Spring核心系列之ApplicationContext

Hello,你們好,今天開始,小弟準備推出Spring系列的博客,但願你們喜歡。關於Spring其實我就不用再多介紹了,作過Web開發的,基本都使用Spring,包括如今比較時尚的Spring cloud微服務架構,其實也是基於Spring boot ,Spring boot 說到底其實仍是傳統的Spring三件套,只是避免了用戶本身配置Bean,而是採用了自動配置,Spring boot後期有時間也專門給你們出一系列博客。這一期做爲Spring的第一篇,先來點基礎的,OK,來套路,文章結構:java

  1. Spring中的Resource接口.
  2. BeanFactory和ApplicationContext
  3. WebApplicationContext

1. Spring中的Resource接口.

其實對於不少業務開發程序員來說,這個接口是比較陌生的,你們知道的是在初始化容器的時候直接指定文件路徑,而後容器就初始化好了,這個Resource接口是Spring提供的,它爲應用提供了更強的底層資源訪問能力。比JDK自帶的File和URL類不知道強了多少。列下類結構: 程序員

說幾個重點的: ClassPathResource: 以類路徑爲相對路勁下的資源 。 FileSystemResource : 以文件系統路徑查找的資源。 ServletContextResource : 以相對於Web應用跟目錄的方式訪問。 ByteArrayResource: 二進制數組表示的資源。 好比如今Web的路徑下又一個Spring的配置文件,咱們能夠這樣加載:

Resource res =new ServletContectResource(/WEB-INF/classes/spring/application.xml);
複製代碼

看到代碼,相信比較敏感的小夥伴應該感受到了,這種加載方式顯然是不合適的,由於在使用不一樣的資源類型時,必須使用相應的Resource資源類,這是比較麻煩的,是否能夠在不現實使用Resource實現類的狀況下,僅經過資源地址的特殊標識就能夠訪問相應的資源呢?Spring這麼偉大的框架,固然是能夠的。Spring不只可以經過"classpath:","file"等資源地址前綴識別不一樣資源類型,還支持Ant風格帶通配符的資源地址。Spring內部會經過資源加載器來根據不一樣的資源路徑選擇相應的Resource實現類。避免的使用者本身選擇實現類。web

1.1 資源地址表達式

先看下Spring內置的一些資源前綴表達的含義: spring

而後Ant風格:

  • ?:匹配文件名中的一個字符.
  • *:匹配文件命中的任意字符.
  • ** :匹配多層路徑.

具體就不舉例子了,Ant風格的通配符太經常使用了。sql

1.2 資源加載器

這些接口我就很少講了,沒什麼實際意義,只說一個,PathMatchingResourcePatternResolver,這個是Spring提供的標準資源加載器,可以支持Ant風格的資源路徑,並根據不一樣前綴類型返回相應的Resource.舉個栗子:

public class GaoshiApplication {

	public static void main(String[] args) throws IOException {

		PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
		Resource[] res =resolver.getResources("file:/Users/zdy/Desktop/sql.txt");
		for (Resource  resource : res){
			System.out.println(resource.getDescription()+"----"+resource.getFilename());
		}
		SpringApplication.run(GaoshiApplication.class, args);
	}
}
複製代碼
輸出結果:
URL [file:/Users/zdy/Desktop/sql.txt]----sql.txt
複製代碼

好了,其實這一小節爲何要給你們講Resource和PathMatchingResourcePatternResolver資源加載器呢,不少人可能感受沒什麼用,反正Spring內部本身使用就完了,跟我不要緊。其實不是的,老鐵們,Spring內部本身使用不假,首先,知道點底層原理很差嗎?其次,你們若是本身有配置文件在classpath下,而後想經過代碼去加載(雖然這種需求很是少),那麼你們就能夠本身使用Spring提供的資源加載器了。這個加載器仍是很方便的,直接根據前綴加載資源,並且還支持Ant通配符。你說厲害不厲害。數組

2. BeanFactory和ApplicationContext

2.1 BeanFactory

BeanFactory,其實不少人聽過,只是沒有用過,你們啓動容器的時候可能都是用的ApplicationContext的某個實現類,因此這個BeanFactory慢慢的都淡了,更別說它的實現類了。說下特性:bash

  1. BeanFactory是延遲加載,若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常;而ApplicationContext則在初始化自身是檢驗,這樣有利於檢查所依賴屬性是否注入;因此一般狀況下咱們選擇使用ApplicationContext。
  2. ApplicationContext繼承自BeanFactory,提供的功能更增強大,通常狀況下都是使用ApplicationContext

而後舉個初始化BeanFactory的例子吧:session

//調用資源加載器加載Spring配置文件
		PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
		Resource res =resolver.getResource("classpath:/application.xml");
		
		//建立默認Spring提供的BeanFactory實現類
		DefaultListableBeanFactory bf =new DefaultListableBeanFactory();
		
		//BeanDefinition 讀取器,專門讀取資源到容器
		XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(bf);
		
		//讀取資源進到容器 
		reader.loadBeanDefinitions(res);
		
		//此時容器初始化完畢後能夠取裏面的bean了.
		bf.getBean("...");
複製代碼

能夠看到,代碼比較繁瑣,並且很囉嗦。BeanFactory的功能還比較弱,因此你們就當瞭解吧。架構

2.2 ApplicationContext

這個ApplicationContext其實就是老鐵們常常說的Spring容器了。由於相對要重要一些,因此列了大體的類繼承圖: app

說下圖中幾個重要的類或接口:

  • ApplicationEventPublisher: 讓容器擁有發佈應用程序上下文事件的功能.
  • ResourcePatternResolver:實現了相似於資源加載器的功能,可以識別特定前綴加Ant風格的路徑並加載到容器中.
  • LifeCycle:管理容器中bean的生命週期。
  • ConfigurableApplicationContext:主要新增了refresh()和close()方法,讓ApplicationContext有用了啓動,關係和刷新上下文的功能。
  • ClassPathXmlApplicationContext與FileSystemXmlApplicationContext:Spring提供的兩個經常使用的ApplicationContext實現類,前者默認從類路徑加載配置文件,後者從文件系統加載。 而後初始化一個ApplicationContext看看:
ApplicationContext ac =new ClassPathXmlApplicationContext("application.xml");
ApplicationContext ac =new FileSystemXmlApplicationContext(/User/Desktop/application.xml);
複製代碼

ClassPathXmlApplicationContext若是沒有前綴默認就是classpath: FileSystemXmlApplicationContext若是沒有前綴默認就是 file:

而後再說一個,Spring容器不只能夠經過xml文件來初始化,@Configuration註解你們應該知道,也是註冊Bean用的,固然了,Spring也提供了相應的AnnotationConfigApplicationContext.

ApplicationContext context =new AnnotationConfigApplicationContext(Config.class);
複製代碼

Config類就是咱們加了@Configuration的類了。

3. WebApplicationContext

其實WebApplicationContext也屬於ApplicationContext,爲何單獨拿出來說呢,由於比較重要。WebApplicationContext是Spring專門爲Web應用準備的。它容許從相對於Web根目錄的路徑中裝載配置文件完成初始化工做。WebApplicationContext與ServletContext能夠相互得到.在非Web應用的環境下,Bean只有singleton和prototype兩種做用域,而WebApplicationContext爲Bean添加了三個新的做用域:request,session,global session。來看下類繼承圖:

最最核心的XmlWebApplicationContext和AnnotationConfigWebApplicationContext,你們猜都應該猜到了,一個是XML配置的,一個是@Configuration配置的。

而後說下WebApplicationContext和ServletContext是如何相互獲取的,其實很簡單,在WebApplicationContext裏有ServletContext成員變量,直接get就完了。在ServletContext裏有一個寫死的attrbute,也是直接get..並且Spring提供了一個WebApplicationContextUtils來封裝了這個寫死的attribute.

其實就是直接調用了ServletContext.getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
        return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    }
複製代碼

而後說下WebApplication的初始化,作過Web的都知道,其實要麼在Web.xml裏面配置一個ContextLoaderListener,要麼配置一個自啓動的LoaderServlet.其實比較簡單了,我展現下ContextLoaderListener.

<!-- 加載spring容器 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/applicationContext-*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
複製代碼

若是不是根據xml文件啓動Spring容器而是根據@Configuration類啓動,其實也很簡單.

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <!-- 加載spring容器 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.zdy.Configuration</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
複製代碼

配置一個contextClass參數ApplicationContext改成AnnotationConfigWebApplicationContext,而後contextConfigLocation不是指定配置文件xml位置了,改成指定Configuration類的位置。就OK了。

最後,須要強調的是,因爲Spring容器自帶的Log4j功能,因此用戶能夠直接將Log4j的配置文件放置在類路徑下,直接就生效了,可是,若是不在類路徑下,須要在Web.xml中手動指定文件的位置和啓動log4j的listener,這裏我就不演示了,須要注意的是,這個log4j的listener或者servlet必須在spring容器的listenier或servlet前面。不要問爲何。就是這麼規定的。不過這點你們不經常使用,因此我只是提一提。

結語

好了,其實你們也看出來了,講Spring的時候我仍是偏向於使用的,Spring的底層深層次的原理其實設計到的很少。Spring這個至尊框架,我以爲先要宏觀使用上先整明白。後期有機會給你們多講點底層實現。喜歡你們多關注接下來的Spring系列文章。Over,Have a good day .

相關文章
相關標籤/搜索