精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

最全面的Spring學習筆記

開發 后端
pring致力于提供一種方法管理你的業務對象。在大量Java EE的應用中,隨處可見Spring。今天我將簡單的介紹一下Spring這個框架。

pring致力于提供一種方法管理你的業務對象。在大量Java EE的應用中,隨處可見Spring。今天我將簡單的介紹一下Spring這個框架。

本文適合讀者:

  • 想學Spring的Java開發者
  • 剛用Spring不久的人

Why

為什么要使用Spring?

Spring主要兩個有功能為我們的業務對象管理提供了非常便捷的方法:

  • DI(Dependency Injection,依賴注入)
  • AOP(Aspect Oriented Programming,面向切面編程)

Java Bean

每一個類實現了Bean的規范才可以由Spring來接管,那么Bean的規范是什么呢?

  • 必須是個公有(public)類
  • 有無參構造函數
  • 用公共方法暴露內部成員屬性(getter,setter)

實現這樣規范的類,被稱為Java Bean。即是一種可重用的組件。

額外補充:
Java 帝國之Java bean (上) 
Java 帝國之Java bean(下)

DI-依賴注入

簡單來說,一個系統中可能會有成千上萬個對象。如果要手工維護它們之間的關系,這是不可想象的。我們可以在Spring的XML文件描述它們之間的關系,由Spring自動來注入它們——比如A類的實例需要B類的實例作為參數set進去。

擴展:Spring 的本質系列(1) — 依賴注入

AOP-面向切面編程

就以日志系統為例。在執行某個操作前后都需要輸出日志,如果手工加代碼,那簡直太可怕了。而且等代碼龐大起來,也是非常難維護的一種情況。這里就需要面向切面來編程

擴展:Spring本質系列(2)-AOP

How

關于Bean

Bean的生命周期

如你所見,在bean準備就緒之前,bean工廠執行了若干啟動步驟。我們對圖進行詳細描述:

  1. Spring對bean進行實例化;
  2. Spring將值和bean的引用注入到bean對應的屬性中;
  3. 如果bean實現了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
  4. 如果bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;
  5. 如果bean實現了ApplicationContextAware接口,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;
  6. 如果bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessBeforeInitialization()方法;
  7. 如果bean實現了InitializingBean接口,Spring將調用它們的after-PropertiesSet()方法。類似地,如果bean使用init-method聲明了初始化方法,該方法也會被調用;
  8. 如果bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessAfterInitialization()方法;
  9. 此時,bean已經準備就緒,可以被應用程序使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷毀;
  10. 如果bean實現了DisposableBean接口,Spring將調用它的destroy()接口方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會被調用。

Bean的作用域

Spring定義了多種Bean作用域,可以基于這些作用域創建bean,包括:

  • 單例(Singleton):在整個應用中,只創建bean的一個實例。
  • 原型(Prototype):每次注入或者通過Spring應用上下文獲取的時候,都會創建一個新的bean實例。
  • 會話(Session):在Web應用中,為每個會話創建一個bean實例。
  • 請求(Rquest):在Web應用中,為每個請求創建一個bean實例。

在代碼里看起來是這樣的:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyIsBean{...}

XML版本:

<bean id="BEANID"
  class = "com.my.beans"
  scope="prototype"
>

在默認情況下,Spring應用上下文中所有bean都是作為以單例(singleton)的形式創建的。也就是說,不管給定的一個bean被注入到其他bean多少次,每次所注入的都是同一個實例。

在大多數情況下,單例bean是很理想的方案。初始化和垃圾回收對象實例所帶來的成本只留給一些小規模任務,在這些任務中,讓對象保持無狀態并且在應用中反復重用這些對象可能并不合理。

有時候,可能會發現,你所使用的類是易變的(mutable),它們會保持一些狀態,因此重用是不安全的。在這種情況下,將class聲明為單例的bean就不是什么好主意了,因為對象會被污染,稍后重用的時候會出現意想不到的問題。

聲明Bean

以下是聲明Bean的注解:

  • @Component 組件,沒有明確的角色
  • @Service 在業務邏輯層使用
  • @Repository 在數據訪問層使用
  • @Controller 在展現層使用(MVC -> Spring MVC)使用
  • 在這里,可以指定bean的id名:Component(“yourBeanName”)
  • 同時,Spring支持將@Named作為@Component注解的替代方案。兩者之間有一些細微的差異,但是在大多數場景中,它們是可以互相替換的。

關于依賴注入

注入Bean的注解

@Autowired Spring提供的注解

不僅僅是對象,還有在構造器上,還能用在屬性的Setter方法上。

不管是構造器、Setter方法還是其他的方法,Spring都會嘗試滿足方法參數上所聲明的依賴。假如有且只有一個bean匹配依賴需求的話,那么這個bean將會被裝配進來。

如果沒有匹配的bean,那么在應用上下文創建的時候,Spring會拋出一個異常。為了避免異常的出現,你可以將@Autowired的required屬性設置為false。

將required屬性設置為false時,Spring會嘗試執行自動裝配,但是如果沒有匹配的bean的話,Spring將會讓這個bean處于未裝配的狀態。但是,把required屬性設置為false時,你需要謹慎對待。如果在你的代碼中沒有進行null檢查的話,這個處于未裝配狀態的屬性有可能會出現NullPointerException。

@Inject注解來源于Java依賴注入規范,該規范同時還為我們定義了@Named注解。在自動裝配中,Spring同時支持@Inject和@Autowired。盡管@Inject和@Autowired之間有著一些細微的差別,但是在大多數場景下,它們都是可以互相替換的。

@Autowired 是最常見的注解之一,但在老項目中,你可能會看到這些注解,它們的作用和@Autowired 相近:

  • @Inject 是JSR-330提供的注解
  • @Resource 是JSR-250提供的注解

條件化的Bean

假設你希望一個或多個bean只有在應用的類路徑下包含特定的庫時才創建。或者我們希望某個bean只有當另外某個特定的bean也聲明了之后才會創建。我們還可能要求只有某個特定的環境變量設置之后,才會創建某個bean。

在Spring 4之前,很難實現這種級別的條件化配置,但是Spring 4引入了一個新的@Conditional注解,它可以用到帶有@Bean注解的方法上。如果給定的條件計算結果為true,就會創建這個bean,否則的話,這個bean會被忽略。

通過ConditionContext,我們可以做到如下幾點:

  • 借助getRegistry()返回的BeanDefinitionRegistry檢查bean定義;
  • 借助getBeanFactory()返回的ConfigurableListableBeanFactory檢查bean是否存在,甚至探查bean的屬性;
  • 借助getEnvironment()返回的Environment檢查環境變量是否存在以及它的值是什么;
  • 讀取并探查getResourceLoader()返回的ResourceLoader所加載的資源;
  • 借助getClassLoader()返回的ClassLoader加載并檢查類是否存在。

處理自動裝配的歧義性

標示首選的bean

在聲明bean的時候,通過將其中一個可選的bean設置為首選(primary)bean能夠避免自動裝配時的歧義性。當遇到歧義性的時候,Spring將會使用首選的bean,而不是其他可選的bean。實際上,你所聲明就是“最喜歡”的bean。

限定自動裝配的bean

設置首選bean的局限性在于@Primary無法將可選方案的范圍限定到唯一一個無歧義性的選項中。它只能標示一個優先的可選方案。當首選bean的數量超過一個時,我們并沒有其他的方法進一步縮小可選范圍。

與之相反,Spring的限定符能夠在所有可選的bean上進行縮小范圍的操作,最終能夠達到只有一個bean滿足所規定的限制條件。如果將所有的限定符都用上后依然存在歧義性,那么你可以繼續使用更多的限定符來縮小選擇范圍。

@Qualifier注解是使用限定符的主要方式。它可以與@Autowired和@Inject協同使用,在注入的時候指定想要注入進去的是哪個bean。例如,我們想要確保要將IceCream注入到setDessert()之中:

@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert){
  this.dessert = dessert;
}

這是使用限定符的最簡單的例子。為@Qualifier注解所設置的參數就是想要注入的bean的ID。所有使用@Component注解聲明的類都會創建為bean,并且bean的ID為首字母變為小寫的類名。因此,@Qualifier(“iceCream”)指向的是組件掃描時所創建的bean,并且這個bean是IceCream類的實例。

實際上,還有一點需要補充一下。更準確地講,@Qualifier(“iceCream”)所引用的bean要具有String類型的“iceCream”作為限定符。如果沒有指定其他的限定符的話,所有的bean都會給定一個默認的限定符,這個限定符與bean的ID相同。因此,框架會將具有“iceCream”限定符的bean注入到setDessert()方法中。這恰巧就是ID為iceCream的bean,它是IceCream類在組件掃描的時候創建的。

基于默認的bean ID作為限定符是非常簡單的,但這有可能會引入一些問題。如果你重構了IceCream類,將其重命名為Gelato的話,那此時會發生什么情況呢?如果這樣的話,bean的ID和默認的限定符會變為gelato,這就無法匹配setDessert()方法中的限定符。自動裝配會失敗。

這里的問題在于setDessert()方法上所指定的限定符與要注入的bean的名稱是緊耦合的。對類名稱的任意改動都會導致限定符失效。

SpringEL

  • Value實現資源的注入

Bean的初始化和銷毀

  • Java配置方式:initMethod和destoryMethod
  • 注解:@PostConstruct和@PreDestory

Profile

提供在不同的環境下使用不同的配置

激活Profile

Spring在確定哪個profile處于激活狀態時,需要依賴兩個獨立的屬性:spring.profiles.active和spring.profiles.default。如果設置了spring.profiles.active屬性的話,那么它的值就會用來確定哪個profile是激活的。但如果沒有設置spring.profiles.active屬性的話,那Spring將會查找spring.profiles.default的值。如果spring.profiles.active和spring.profiles.default均沒有設置的話,那就沒有激活的profile,因此只會創建那些沒有定義在profile中的bean。

使用profile進行測試

當運行集成測試時,通常會希望采用與生產環境(或者是生產環境的部分子集)相同的配置進行測試。但是,如果配置中的bean定義在了profile中,那么在運行測試時,我們就需要有一種方式來啟用合適的profile。

Spring提供了@ActiveProfiles注解,我們可以使用它來指定運行測試時要激活哪個profile。在集成測試時,通常想要激活的是開發環境的profile。

比如Profile(“dev”)

Application Event

使用Application Event可以做到Bean與Bean之間的通信

Spring的事件需要遵循如下流程:

  • 自定義事件,集成ApplicationEvent
  • 定義事件監聽器,實現ApplicationListener
  • 使用容器發布事件

關于AOP

名詞介紹

通知(Advice)

通知定義了切面是什么以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。它應該應用在某個方法被調用之前?之后?之前和之后都調用?還是只在方法拋出異常時調用?

Spring切面可以應用5種類型的通知:

  • 前置通知(Before):在目標方法被調用之前調用通知功能;
  • 后置通知(After):在目標方法完成之后調用通知,此時不會關心方法的輸出是什么;
  • 返回通知(After-returning):在目標方法成功執行之后調用通知;
  • 異常通知(After-throwing):在目標方法拋出異常后調用通知;
  • 環繞通知(Around):通知包裹了被通知的方法,在被通知的方法調用之前和調用之后執行自定義的行為。

對應注解:

注  解 通  知
@After 通知方法會在目標方法返回或拋出異常后調用
@AfterReturning 通知方法會在目標方法返回后調用
@AfterThrowing 通知方法會在目標方法拋出異常后調用
@Around 通知方法會將目標方法封裝起來
@Before 通知方法會在目標方法調用之前執行

連接點(Join point)

連接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,并添加新的行為。

切點(Pointcut)

如果說通知定義了切面的“什么”和“何時”的話,那么切點就定義了“何處” 。切點的定義會匹配通知所要織入的一個或多個連接點。我們通常使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。有些AOP框架允許我們創建動態的切點,可以根據運行時的決策(比如方法的參數值)來決定是否應用通知。

切面(Aspect)

通知+切點=切面

引入(Introduction)

引入允許我們向現有的類添加新方法或屬性

織入(Weaving)

織入是把切面應用到目標對象并創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。在目標對象的生命周期里有多個點可以進行織入:

  • 編譯期:切面在目標類編譯時被織入。這種方式需要特殊的編譯器。AspectJ的織入編譯器就是以這種方式織入切面的。
  • 類加載期:切面在目標類加載到JVM時被織入。這種方式需要特殊的類加載器(ClassLoader),它可以在目標類被引入應用之前增強該目標類的字節碼。AspectJ 5的加載時織入(load-time weaving,LTW)就支持以這種方式織入切面。
  • 運行期:切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態地創建一個代理對象。Spring AOP就是以這種方式織入切面的。

Spring對AOP的支持:

  1. 基于代理的經典Spring AOP;
  2. 純POJO切面(4.x版本需要XML配置);
  3. @AspectJ注解驅動的切面;
  4. 注入式AspectJ切面(適用于Spring各版本)。

前三種都是Spring AOP實現的變體,Spring AOP構建在動態代理基礎之上,因此,Spring對AOP的支持局限于方法攔截。也就是說,AspectJ才是王道。

另外在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。如下圖所示,代理類封裝了目標類,并攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法之前,會執行切面邏輯。直到應用需要被代理的bean時,Spring才創建代理對象。 如果使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載所有bean的時候,Spring才會創建被代理的對象。因為Spring運行時才創建代理對象,所以我們不需要特殊的編譯器來織入Spring AOP的切面。

例子

public interface Performance(){
  public void perform();
}

現在來寫一個切點表達式,這個表達式能夠設置當perform()方法執行時觸發通知的調用。

execution(* concert.Performance.perform(..))
//execution:在方法執行時觸發
//*:返回任意類型
//concert.Performance:方法所屬類
//perform:方法名
//(..):使用任意參數

不僅如此,還可以寫的更復雜一點

execution(* concert.Performance.perform(..)&&within(concert.*))
//增加了一個與操作,當concert包下的任意類方法被調用時也會觸發

在切點中選擇bean

execution(*concert.Performance.perform()) and bean('woodstock')
//限定bean id為woodstock

來個完整的切面

@Aspect
public class Audience{
  @Before("execution(**concert.Performance.perform(..))")
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  @Before("execution{** concert.Performance.perform{..}}")
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  @AfterReturning("execution{** concert.Performance.perform{..}}")
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("execution{** concert.Performance.perform{..}}")
  public void demanRefund(){
    System.out.println("Demanding a refund");
  }
}

可以簡化一下

@Aspect
public class Audience{
  //避免頻繁使用切點表達式
  @Pointcut("execution(** concert.Performance.perform(..))")
  public void performance(){}

  @Before("performance()")
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  @Before("performance()")
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  @AfterReturning("performance()")
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("performance()")
  public void demanRefund(){
    System.out.println("Demanding a refund");
  }
}

XML中聲明切面

AOP配置元素 用途
<aop:advisor> 定義AOP通知器
<aop:after> 定義AOP后置通知(不管被通知的方法是否執行成功)
<aop:after-returning> 定義AOP返回通知
<aop:after-throwing> 定義AOP異常通知
<aop:around> 定義AOP環繞通知
<aop:aspect> 定義一個切面
<aop:aspectj-autoproxy> 啟用@AspectJ注解驅動的切面
<aop:before> 定義一個AOP前置通知
<aop:config> 頂層的AOP配置元素。大多數的<aop:*>元素必須包含在<aop:config>元素內
<aop:declare-parents> 以透明的方式為被通知的對象引入額外的接口
<aop:pointcut> 定義一個切點

來個栗子

public class Audience{
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  public void demandRefund(){
    System.out.println("Demanding a refund");
  }
}

通過XML將無注解的Audience聲明為切面

<aop:config>
  <aop:aspect ref="audience">
    <aop:before       pointcut ="execution(** concert.Performance.perform(..))"       method="sillenceCellPhones"/>
    <aop:before       pointcut ="execution(** concert.Performance.perform(..))"       method="taskSeats"/>
    <aop:after-returning       pointcut ="execution(** concert.Performance.perform(..))"       method="applause"/>
    <aop:After-throwing         pointcut ="execution(** concert.Performance.perform(..))"         method="demanRefund"/>
  </aop:aspect>
</aop:config>

AspectJ關于Spring AOP的AspectJ切點,最重要的一點就是Spring僅支持AspectJ切點指示器(pointcut designator)的一個子集。讓我們回顧下,Spring是基于代理的,而某些切點表達式是與基于代理的AOP無關的。下表列出了Spring AOP所支持的AspectJ切點指示器。

Spring借助AspectJ的切點表達式語言來定義Spring切面

AspectJ指示器 描  述
arg() 限制連接點匹配參數為指定類型的執行方法
@args() 限制連接點匹配參數由指定注解標注的執行方法
execution() 用于匹配是連接點的執行方法
this() 限制連接點匹配AOP代理的bean引用為指定類型的類
target 限制連接點匹配目標對象為指定類型的類
@target() 限制連接點匹配特定的執行對象,這些對象對應的類要具有指定類型的注解
within() 限制連接點匹配指定的類型
@within() 限制連接點匹配指定注解所標注的類型(當使用Spring AOP時,方法定義在由指定的注解所標注的類里)
@annotation 限定匹配帶有指定注解的連接點

Spring高級特性

由于Spring特殊的依賴注入技巧,導致Bean之間沒有耦合度。

但是Bean有時需要使用spring容器本身的資源,這時你的Bean必須意識到Spring容器的存在。所以得使用Spring Aware,下面來看看Spring Aware提供的接口

BeanNameAware 獲得到容器中Bean的名稱
BeanFactory 獲得當前的bean factory,這樣可以調用容器的服務
ApplicationContextAware* 當前application context,這樣可以調用容器的服務
MessageSourceAware 獲得Message source
ApplicationEventPublisherAware 應用時間發布器,可以發布時間,
ResourceLoaderAware 獲得資源加載器,可以獲得外部資源文件

@TaskExecutor

這樣可以實現多線程和并發編程。通過@EnableAsync開啟對異步任務的支持,并通過實際執行的Bean的方法始中使用@Async注解來聲明其是一個異步任務

@Scheduled 計劃任務

首先通過在配置類注解@EnableScheduling來開啟對計劃任務的支持,然后在要執行計劃任務的方法上注解@Scheduled,聲明這是一個計劃任務

@Conditional

根據滿足某一個特定條件創建一個特定的Bean。

組合注解與元注解

元注解就是可以注解到別的注解上的注解,被注解的注解稱之為組合注解,組合注解具備注解其上的元注解的功能。

@Enable*注解的工作原理

通過觀察這些@Enable*注解的源碼,我們發現所有的注解都有一個@Import注解,@Import是用來導入配置類的,這也就意外著這些自動開啟的實現其實是導入了一些自動配置的Bean。這些導入配置的方式主要范圍以下三種類型:

  • 第一類:直接導入配置類
  • 第二類:依據條件選擇配置類
  • 第三類:動態注冊Bean

What

簡單的分析一下Spring。

Spring 框架中的核心組件只有三個:Core、Context 和 Bean。它們構建起了整個 Spring 的骨骼架構。沒有它們就不可能有 AOP、Web 等上層的特性功能。下面也將主要從這三個組件入手分析 Spring。

Spring的設計理念

用過Spring的同學都知道Bean在Spring的作用是非常重要的。通過一系列簡單的配置來滿足類與類之間的依賴關系——這叫做依賴注入。而依賴注入的關系是在一個叫IOC的容器中進行管理。

核心組件

我們說到Spring 框架中的核心組件只有三個:Core、Context 和 Bean。那么Core和Context是如何協作的呢?

我們知道 Bean 包裝的是 Object,而 Object 必然有數據,如何給這些數據提供生存環境就是 Context 要解決的問題,對 Context 來說他就是要發現每個 Bean 之間的關系,為它們建立這種關系并且要維護好這種關系。所以 Context 就是一個 Bean 關系的集合,這個關系集合又叫 Ioc 容器 ,一旦建立起這個 Ioc 容器后 Spring 就可以為你工作了。那 Core 組件又有什么用武之地呢?其實 Core 就是發現、建立和維護每個 Bean 之間的關系所需要的一些列的工具。

解析核心組件

Bean

前面已經說明了 Bean 組件對 Spring 的重要性,下面看看 Bean 這個組件式怎么設計的。Bean 組件在 Spring 的 org.springframework.beans 包下。這個包下的所有類主要解決了三件事:Bean 的定義、Bean 的創建以及對 Bean 的解析。對 Spring 的使用者來說唯一需要關心的就是 Bean 的創建,其他兩個由 Spring 在內部幫你完成了,對你來說是透明的。

Spring Bean 的創建時典型的工廠模式,他的頂級接口是 BeanFactory,下圖是這個工廠的繼承層次關系:

BeanFactory 有三個子類:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。但是從上圖中我們可以發現最終的默認實現類是 DefaultListableBeanFactory,他實現了所有的接口。那為何要定義這么多層次的接口呢?查閱這些接口的源碼和說明發現,每個接口都有他使用的場合,它主要是為了區分在 Spring 內部在操作過程中對象的傳遞和轉化過程中,對對象的數據訪問所做的限制。例如 ListableBeanFactory 接口表示這些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關系的,也就是每個 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定義 Bean 的自動裝配規則。這四個接口共同定義了 Bean 的集合、Bean 之間的關系、以及 Bean 行為。

Context

ApplicationContext 是 Context 的頂級父類,他除了能標識一個應用環境的基本信息外,他還繼承了五個接口,這五個接口主要是擴展了 Context 的功能。下面是 Context 的類結構圖:

從上圖中可以看出 ApplicationContext 繼承了 BeanFactory,這也說明了 Spring 容器中運行的主體對象是 Bean,另外 ApplicationContext 繼承了 ResourceLoader 接口,使得 ApplicationContext 可以訪問到任何外部資源,這將在 Core 中詳細說明。

ApplicationContext 的子類主要包含兩個方面:

  • ConfigurableApplicationContext 表示該 Context 是可修改的,也就是在構建 Context 中用戶可以動態添加或修改已有的配置信息,它下面又有多個子類,其中最經常使用的是可更新的 Context,即 AbstractRefreshableApplicationContext類。
  • WebApplicationContext 顧名思義,就是為 web 準備的 Context 他可以直接訪問到 ServletContext,通常情況下,這個接口使用的少。

再往下分就是按照構建 Context 的文件類型,接著就是訪問 Context 的方式。這樣一級一級構成了完整的 Context 等級層次。

總體來說 ApplicationContext 必須要完成以下幾件事:

  • 標識一個應用環境
  • 利用 BeanFactory 創建 Bean 對象
  • 保存對象關系表
  • 能夠捕獲各種事件

Context 作為 Spring 的 IOC 容器,基本上整合了 Spring 的大部分功能,或者說是大部分功能的基礎。

Core

Core 組件作為 Spring 的核心組件,他其中包含了很多的關鍵類,其中一個重要組成部分就是定義了資源的訪問方式。這種把所有資源都抽象成一個接口的方式很值得在以后的設計中拿來學習。下面就重要看一下這個部分在 Spring 的作用。

從上圖可以看出 Resource 接口封裝了各種可能的資源類型,也就是對使用者來說屏蔽了文件類型的不同。對資源的提供者來說,如何把資源包裝起來交給其他人用這也是一個問題,我們看到 Resource 接口繼承了 InputStreamSource 接口,這個接口中有個 getInputStream 方法,返回的是 InputStream 類。這樣所有的資源都被可以通過 InputStream 這個類來獲取,所以也屏蔽了資源的提供者。另外還有一個問題就是加載資源的問題,也就是資源的加載者要統一,從上圖中可以看出這個任務是由 ResourceLoader 接口完成,他屏蔽了所有的資源加載者的差異,只需要實現這個接口就可以加載所有的資源,他的默認實現是 DefaultResourceLoader

那么, Context 和 Resource 是如何建立關系的?

從上圖可以看出,Context 是把資源的加載、解析和描述工作委托給了 ResourcePatternResolver 類來完成,他相當于一個接頭人,他把資源的加載、解析和資源的定義整合在一起便于其他組件使用。Core 組件中還有很多類似的方式。

小結

該文章算是以前學習Spring時候的一些筆記整理。如果有任何錯誤或者不解的地方,請留言給我。這是一個令我們可以一起學習進步的機會。

責任編輯:王雪燕 來源: 泊浮目
相關推薦

2013-05-27 14:06:14

Android開發移動開發Intent機制

2015-12-16 10:30:18

前端開發指南

2015-09-18 16:55:45

云計算

2012-05-18 11:40:40

神舟筆記本

2015-11-17 09:30:23

程序員招聘建議

2016-01-28 14:41:06

CC++編碼

2015-01-12 09:40:41

iOS學習資料整理

2015-01-12 12:12:00

iOS學習資料整理

2020-04-14 10:50:47

FlutterGithub

2020-08-06 10:45:30

JavaSpring面試題

2010-07-02 14:16:42

UML

2016-01-07 10:26:49

全球程序員研究報告

2010-07-12 14:47:53

UML建模

2013-06-27 15:14:56

搜狗手機地圖

2018-03-27 09:31:21

數據庫MySQL線程池

2011-12-15 10:49:57

Broadcom汽車以太網

2017-11-14 19:19:07

人工智能自然語言處理百度

2015-06-23 17:35:42

甲骨文云計算

2022-10-11 10:08:35

英特爾FGPA

2018-06-28 15:40:04

AI 數據機器學習
點贊
收藏

51CTO技術棧公眾號

欧美男生操女生| 26uuu欧美日本| 久久综合网hezyo| 少妇献身老头系列| 在线手机中文字幕| 91丨porny丨中文| 成人久久一区二区三区| 精品无码免费视频| 成人嫩草影院| 亚洲福利在线看| av网站在线不卡| 久久亚洲资源| 日本一区二区综合亚洲| 丁香五月网久久综合| 青青视频在线免费观看| 午夜精品影院| 色偷偷噜噜噜亚洲男人的天堂| 成人午夜视频在线观看免费| 六十路在线观看| 国产伦理精品不卡| 欧洲精品在线视频| 欧美极品aaaaabbbbb| 欧美一站二站| 精品国产免费视频| 亚洲美女性囗交| 韩日成人影院| 亚洲一区二区av电影| 亚洲精品欧美精品| 人操人视频在线观看| 国产传媒久久文化传媒| 国产欧美日韩精品在线观看| 成人免费毛片男人用品| 欧美日韩一区二区高清| 中文字幕免费精品一区| 玖玖爱在线观看| 国产66精品| 日韩欧美不卡在线观看视频| 99热一区二区| 日本欧美一区| 一本到不卡精品视频在线观看| 青青草国产精品| 色一情一乱一乱一区91av| 国产一区二区三区精品视频| 国产91色在线免费| 国产精品999在线观看| 国内自拍一区| 九九热这里只有精品免费看| 亚洲熟女毛茸茸| 三区四区不卡| 中文字幕日韩欧美在线 | 一区二区黄色片| 亚洲第一二区| 欧美一级艳片视频免费观看| 天天干天天玩天天操| 粉嫩av一区二区三区四区五区| 亚洲欧美国产高清| 久久免费视频2| 黄色成人影院| 一区二区三区91| 日韩欧美视频免费在线观看| 天堂av最新在线| 亚洲一区二区三区视频在线播放| 久久香蕉综合色| 色网站在线免费观看| 91在线国内视频| 欧美影视一区二区| 福利片在线看| 中文字幕五月欧美| 色哺乳xxxxhd奶水米仓惠香| 羞羞网站在线看| 婷婷中文字幕综合| 黄色一级免费大片| 国产精品亚洲综合在线观看| 欧美一区二区三区喷汁尤物| 潘金莲一级淫片aaaaa| 成人高潮a毛片免费观看网站| 在线亚洲一区二区| 97公开免费视频| 高清一区二区中文字幕| 日韩精品中午字幕| 国产福利在线观看视频| 国产一区二区三区四区五区传媒| 精品国产sm最大网站免费看| 加勒比精品视频| 欧美三级美国一级| www国产精品视频| 久草网视频在线观看| 翔田千里一区二区| 国产日韩精品综合网站| 亚洲女同志亚洲女同女播放| 99久久综合精品| 色婷婷精品国产一区二区三区| 欧美一区二区三区激情| 国产偷国产偷亚洲高清人白洁| 超碰国产精品久久国产精品99| 精品国产乱子伦| 久久69国产一区二区蜜臀| 成人激情直播| 黄色av网址在线免费观看| 中文字幕 久热精品 视频在线| 欧美男人的天堂| 国产在线69| 色综合天天综合网天天狠天天| 高清无码视频直接看| 在线观看精品| 日韩一级片网站| 蜜臀久久99精品久久久久久| 欧美日韩亚洲一区| 国产中文欧美精品| 日韩在线无毛| 亚洲一区av在线| 色婷婷一区二区三区av免费看| 日本另类视频| 亚洲黄色在线观看| 特一级黄色录像| 日本在线不卡一区| 久久亚洲午夜电影| 国产探花视频在线观看| 5858s免费视频成人| 成人网站免费观看| 激情亚洲成人| av日韩免费电影| 调教视频免费在线观看| 色欧美日韩亚洲| 少妇精品一区二区| 国内精品福利| 91成人免费观看| 久久久久久久久免费视频| 91久久奴性调教| 黄色国产在线观看| 91久久亚洲| 国产福利久久精品| 在线视频中文字幕第一页| 欧美日韩一级片在线观看| 日韩网站在线播放| 中文日韩在线| 精品日本一区二区| 美女的胸无遮挡在线观看| 日韩精品一区二区三区蜜臀 | 青草久久视频| 久久久久久久久久国产| www.亚洲欧美| 综合欧美一区二区三区| 免费一区二区三区在线观看| 国产精品手机在线播放| 国产精品aaa| 国产精品二线| 91传媒视频在线播放| 大又大又粗又硬又爽少妇毛片| 国产精品久久久久无码av| 国产精品欧美久久久| 国产香蕉在线| 欧美天堂一区二区三区| 欧美成人另类视频| 男人的天堂久久精品| 中文字幕剧情在线观看一区| 色综合视频一区二区三区44| 中文字幕欧美在线| 一级片免费网站| 亚洲乱码国产乱码精品精98午夜| 国产黄色特级片| 欧美日一区二区| 91青草视频久久| 欧美日韩经典丝袜| 亚洲精品电影久久久| 精品国产午夜福利| 中文字幕欧美三区| 手机av在线免费| 欧美黄免费看| 久久涩涩网站| www.国产精品| 欧美老女人性视频| 色噜噜一区二区三区| 一本色道久久综合亚洲aⅴ蜜桃| 欧美一级片在线免费观看| 亚洲第一黄色| 日韩高清国产精品| gogo大尺度成人免费视频| 色综合天天综合网国产成人网| 精品一区二三区| 中文字幕字幕中文在线中不卡视频| 国产又粗又猛又爽又黄的网站| 麻豆影视国产在线观看| 日韩精品一区二区三区视频在线观看 | 日韩精品视频中文字幕| 国模精品视频一区二区三区| 欧美日本韩国一区二区| 欧美区一区二区三区| 精品视频一区二区在线观看| 日韩av无码中文字幕| 日本一区二区不卡视频| 国产综合内射日韩久| 国产精品视频| 中文字幕av久久| 色天下一区二区三区| 国产又爽又黄的激情精品视频 | 农村妇女精品一二区| 日韩精品水蜜桃| 国产欧美日韩在线播放| 欧美成人xxxx| 4438全国亚洲精品在线观看视频| 欧美一级特黄aaaaaa| 色综合久久久久综合| 玖玖爱免费视频| 国产欧美视频在线观看| 国产精品99精品无码视亚| 日本中文字幕一区二区有限公司| 日韩欧美亚洲在线| 九九热hot精品视频在线播放| 久久久女人电视剧免费播放下载| 亚洲国产精品久久久久久6q | 国产精品一区二区三区四| 亚洲国产精华液网站w| 中文字幕免费高清视频| 精品午夜久久福利影院| 精品国产免费av| 日韩视频在线观看| 久久综合婷婷综合| 日韩一区二区三区精品| 国产精品男女猛烈高潮激情| heyzo一区| 久久九九亚洲综合| 福利在线播放| 亚洲男女性事视频| 手机看片一区二区三区| 日韩一区二区免费电影| 国产精品成人无码| 色哟哟一区二区三区| 日韩精品视频免费看| 亚洲自拍偷拍麻豆| 一区视频免费观看| 亚洲人精品午夜| 国产又粗又长又黄的视频| 久久九九久精品国产免费直播| 男女曰b免费视频| 国产日韩欧美一区在线 | 97精品视频在线| 亚洲性图自拍| 久久国产加勒比精品无码| 欧美精品日韩少妇| 中文字幕久精品免费视频| 番号集在线观看| 亚洲午夜久久久久久久| 久青草国产在线| 日韩福利在线播放| 日韩在线无毛| 国产一区二区三区久久精品| 国产永久免费高清在线观看| 亚洲人成电影网站色www| 日韩有码第一页| 亚洲国产精品久久久久秋霞蜜臀 | 天天色天天综合| 日本一区二区高清| 色撸撸在线视频| 亚洲欧洲国产日韩| www.超碰在线观看| 亚洲一区二区三区四区在线| 日韩av免费网址| 懂色av一区二区三区| 亚洲综合久久网| 欧美在线视频不卡| 在线观看日批视频| 欧美一区二区三区公司| 人妻精品无码一区二区| 亚洲国产天堂网精品网站| 三级在线播放| 日韩亚洲第一页| 男男gaygays亚洲| 欧美一级电影久久| 成人国产一区| 亚洲自拍高清视频网站| 国产图片一区| 色女孩综合网| 欧美日韩一区二区国产| 韩国日本在线视频| 激情综合色丁香一区二区| 日韩av成人网| 久久老女人爱爱| www.97视频| 激情亚洲一区二区三区四区| 91青青草视频| 日韩三区在线观看| 无套内谢的新婚少妇国语播放| 欧美一级二级三级蜜桃| 亚洲欧洲成人在线| 久久精品国产亚洲| 交100部在线观看| 国产在线一区二区三区| 国产亚洲成av人片在线观黄桃| 成人黄色免费在线观看| 久久电影在线| 一区二区三区一级片| 亚洲三级国产| 国产又黄又猛的视频| 成人h精品动漫一区二区三区| 亚洲午夜精品在线观看| 91美女精品福利| 中文字幕av播放| 色哦色哦哦色天天综合| 亚洲风情第一页| 色婷婷综合久久久久| 中文字幕乱码中文乱码51精品| 91国产美女视频| 日韩欧美激情| 热舞福利精品大尺度视频| 欧美日韩1区2区3区| 妺妺窝人体色www在线观看| 成人免费毛片嘿嘿连载视频| 国产精品美女高潮无套| 午夜影院久久久| 国产视频一二三四区| 亚洲一区999| 日产福利视频在线观看| www.久久草| 久久久久亚洲| 午夜在线观看av| 99国产精品国产精品毛片| 五月天婷婷色综合| 欧美色图免费看| 黄色av免费在线观看| 97色在线观看| 日本黄色播放器| 蜜桃视频一区二区三区在线观看| 亚洲图色中文字幕| 国产日韩精品一区二区浪潮av| 殴美一级黄色片| 一本到12不卡视频在线dvd| 国产香蕉精品视频一区二区三区| 四虎电影院在线观看| 久久国产精品影视| 色999韩欧美国产综合俺来也| 91国产在线免费观看| 91视频综合| 手机看片一级片| 欧美国产日韩在线观看| 麻豆精品久久久久久久99蜜桃| 欧美色视频在线| 国产中文字幕在线| 日韩av电影在线免费播放| 三级精品视频| 成人综合视频在线| 91丨porny丨中文| 天天干天天干天天操| 日韩精品免费观看| 自拍网站在线观看| 欧美高清性xxxxhd | 香蕉视频免费版| 青青国产91久久久久久| 亚洲av毛片基地| 欧美日韩在线综合| 日韩黄色影院| 国产美女精品视频免费观看| 国产精品99久久久久久动医院| 久激情内射婷内射蜜桃| 成人精品视频一区二区三区 | 亚洲日本电影在线| 国产精品视频a| 九九久久久久久久久激情| 成人资源在线播放| 久久精品视频16| 久久精品视频网| 中文字幕av影视| 久久中文字幕国产| jizz性欧美23| 欧美日韩第二页| 国产欧美精品区一区二区三区 | 粉嫩av免费一区二区三区| 黄色成人在线网站| 性农村xxxxx小树林| 懂色av影视一区二区三区| 欧美男男激情freegay| 国产精品狼人色视频一区| 亚洲91视频| 玖草视频在线观看| 欧美综合一区二区三区| 国产精品久久久久久福利| 国产伦精品一区二区三区在线| 午夜精品久久99蜜桃的功能介绍| av网站在线不卡| 一区二区高清视频在线观看| 视频一区二区三区国产 | 久久久一区二区三区四区| 日韩激情在线视频| 69堂精品视频在线播放| 91精品国产吴梦梦| 91免费国产在线| 国产情侣自拍小视频| 91爱视频在线| 小小影院久久| www.色天使| 欧美一级一区二区| 午夜日韩成人影院| 日韩视频一二三| 久久久午夜精品| 精品人妻无码一区二区色欲产成人| 色先锋资源久久综合5566| 韩漫成人漫画| 91动漫在线看| 日韩一区中文字幕| 国产在线自天天|