激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 解析Java的Spring框架的基本結(jié)構(gòu)

解析Java的Spring框架的基本結(jié)構(gòu)

2020-04-11 14:29liweisnake JAVA教程

這篇文章主要介紹了Java的Spring框架的基本結(jié)構(gòu),作者從Spring的設(shè)計角度觸發(fā)解析其基礎(chǔ)的架構(gòu)內(nèi)容,需要的朋友可以參考下

   在java屆,有位名叫Rod Johnson的牛人,發(fā)現(xiàn)最初的java企業(yè)級開發(fā)處于混沌狀態(tài)。

   于是,它決心編寫一個能夠解決問題的通用的基礎(chǔ)架構(gòu)。

   因為它深信面向接口編程能夠?qū)⒆兓刂频阶钚?,同時也利于擴展和變化。于是,它編寫了如下的接口。 

解析Java的Spring框架的基本結(jié)構(gòu)

   在混沌狀態(tài)最先要創(chuàng)造的是一切對象的母親BeanFactory,有了它,就能夠得到一切它孕育的對象和屬性,也就是說首先要造蓋亞--大地之母。

   有了最初的母親BeanFactory,johnson想,如果我要得到一組Bean對象而不單單是某個或某幾個呢?另外,如果母親的孩子也要孕育對象呢?于是,johnson創(chuàng)造了ListableBeanFactory以操作一組bean對象,比如getBeansOfType就能夠根據(jù)得到同類型的一組Bean;創(chuàng)造了HierarchicalBeanFactory來解決多個BeanFactory的層次問題,比如getParentBeanFactory就能夠得到BeanFactory的父Factory。

   這個BeanFactory最終是要在某個應(yīng)用上使用的,那么,需要給予BeanFactory在一個應(yīng)用中活動的能力。在BeanFactory中,只需要考慮跟bean相關(guān)的行為,比如怎么得到bean,bean的類型等;而如果要賦予其在應(yīng)用中的能力,則就需要考慮更多,比如應(yīng)用的名字,啟動時間,id等等跟應(yīng)用本身相關(guān)的行為和屬性,于是johnson想到了創(chuàng)造ApplicationContext。johnson想,這個ApplicationContext一定要能做許多事,要能夠處理參數(shù)化和國際化的文本信息,于是增加了MessageSource接口;要能發(fā)布事件以便解耦組件,于是有了ApplicationEventPublisher接口;要能得到資源文件,于是有了ResourcePatternResolver接口;要能有在不同環(huán)境有不同處理對象的能力,于是有了EnvironmentCapable接口。

   ApplicationContext繼承了所有這些接口。

   但是最重要的是,無論是BeanFactory還是ApplicationContext,它們都需要有可配置的能力,于是有了子接口ConfigurableBeanFactory和ConfigurableApplicationContext;另外,web在當(dāng)時是非常重要的趨勢,而且相比其他應(yīng)用有些獨特,需要得到ServletContext,于是有了WebApplicationContext。

   到目前為止,johnson都是面向接口進行行為的抽象思考,并未具體實現(xiàn)他們。

   看著創(chuàng)造出來的BeanFactory和ApplicationContext,johnson意識到這一天的工作遠遠沒有結(jié)束,因為并沒有真正解決怎么能夠讓整套體系運轉(zhuǎn)起來,于是,johnson開始思索如何實現(xiàn)他們。

   johoson首先想到的還是這個實現(xiàn)應(yīng)該具備什么能力?當(dāng)然要把之前提到的AutowireCapableBeanFactory,ListableBeanFactory和ConfigurableBeanFactory都包括進去。因此創(chuàng)造了ConfigurableListableBeanFactory。其次,需要考慮對于bean對象的幾種能力,一是起別名的能力;二是保存單例對象的能力;三是緩存的能力;他們分別在SimpleAliasRegistry類,DefaultSingletonBeanRegistry類和FactoryBeanRegistrySupport類中實現(xiàn)。

解析Java的Spring框架的基本結(jié)構(gòu)

   最終,創(chuàng)造出了DefaultListableBeanFactory,它是spring中一切ioc工廠的原型,是BeanFactory第一個真正的孩子,這個孩子非常重要,已經(jīng)成為獨立的創(chuàng)建ioc容器的基礎(chǔ),如果有擴展和使用,大多是繼承它或者組合使用它。

  如果要初始化一個DefaultListableBeanFactory,可以用如下代碼

?
1
2
3
4
ClassPathResource res = new ClassPathResource("applicationContext.xml");
    DefaultListableBeanFactory f = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader r = new XmlBeanDefinitionReader(f);
    r.loadBeanDefinitions(res);

  接下來johnson想,BeanFactory有了一個功能比較全面的默認實現(xiàn),那么ApplicationContext呢?于是johnson孜孜不倦的創(chuàng)造了3個重要的ApplicationContext實現(xiàn):FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigWebApplicationContext(其實還有很多,比如處理portlet的, 處理web的)
解析Java的Spring框架的基本結(jié)構(gòu)

    johnson最先考慮的是如何去做spring的啟動流程,它應(yīng)該放到一個比較抽象的層次以便下層的所有類能夠復(fù)用。于是他用一個AbstractApplicationContext實現(xiàn)了ConfigurableApplicationContext。還有一個很重要的功能,即將一個文件以資源的形式加載進來,這需要將資源抽象為Resource類,將定位資源的具體實現(xiàn)抽象到ResourceLoader,AbstractApplicationContext同樣需要繼承DefaultResourceLoader以提供這個功能。AbstractApplicationContext完成了整個啟動流程(上帝將它安排在第二天完成),唯獨沒有做對BeanFactory的管理。于是,它的子類AbstractRefreshableApplicationContext專門做了這件事,實現(xiàn)了refreshBeanFactory, closeBeanFactory, getBeanFactory專門對BeanFactory的生命周期做了一些管理,但是AbstractRefreshableApplicationContext仍然沒有加載所有配置好的Bean。到哪里加載配置好的資源,實際上到了下層的子類去做,比如FileSystemXmlApplicationContext,就是到文件系統(tǒng)去讀一個xml形式的applicationContext;ClassPathXmlApplicationContext則是到類加載路徑下去讀這個applicationContext。而AnnotationConfigWebApplicationContext則從類文件的annotation中加載bean,spring的掃描也從此開始。

  看著主要的框架已經(jīng)建立起來,johnson滿意的笑著睡著了。
 
   頭一日,johnson完成了一個spring的整體框架。

  第二日,johnson準備實際去處理前面遺留的問題。比如spring的容器初始化過程。如圖,johnson將這個過程分為很多子過程,這些子過程都在圍繞著如何將bean載入這一宏偉的目標(biāo)而努力。

解析Java的Spring框架的基本結(jié)構(gòu)

    這個過程放在AbstractApplicationContext中的refresh方法中。代碼如下,johnson將refresh的過程分為很多子過程,并且這些子過程在同一個抽象層級上,這種寫法是為了給后人一個榜樣。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();
 
    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);
 
    try {
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);
 
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);
 
      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);
 
      // Initialize message source for this context.
      initMessageSource();
 
      // Initialize event multicaster for this context.
      initApplicationEventMulticaster();
 
      // Initialize other special beans in specific context subclasses.
      onRefresh();
 
      // Check for listener beans and register them.
      registerListeners();
 
      // Instantiate all remaining (non-lazy-init) singletons.
      finishBeanFactoryInitialization(beanFactory);
 
      // Last step: publish corresponding event.
      finishRefresh();
    }
 
    catch (BeansException ex) {
      // Destroy already created singletons to avoid dangling resources.
      destroyBeans();
 
      // Reset 'active' flag.
      cancelRefresh(ex);
 
      // Propagate exception to caller.
      throw ex;
    }
  }
}

  如果更高層次一些看,實際上這些過程圍繞著幾個方面來做:1. 刷新的生命周期;2. 對beanFactory的初始化及準備;3. 生成并注冊beanDefinition;4. beanFactory后處理器;5.設(shè)置消息,事件及監(jiān)聽器。
  1. 刷新的生命周期

解析Java的Spring框架的基本結(jié)構(gòu)

    prepareRefresh,這個過程主要記錄日志表示spring啟動了,初始化property資源(比如serlvet中一些資源初始化),以及property資源的驗證(比如只寫了key沒有value)。

  onRefresh,目的是提供給一些特殊的ApplicationContext,使他們有能夠在刷新過程中能夠擴展的能力。目前使用到的大多是為servlet application context設(shè)置theme

  finishRefresh,做一些收尾的工作,如初始化LifecycleProcessor,發(fā)布refresh結(jié)束的事件等。

  cancelRefresh,主要是在異常產(chǎn)生時將當(dāng)前的狀態(tài)改變?yōu)榉莂ctive。

  2. 對beanFactory的初始化及準備

  johnson想,我們應(yīng)該讓beanFactory在初始化時就把bean透明的加載并注冊好,這樣對外界而言,我的封裝就非常成功,因此這步實際上做了很多事。下圖省略了許多步驟,只列出關(guān)鍵點。

  AbstractApplicationContext會調(diào)用refreshBeanFactory,它首先會檢查并關(guān)閉已有的beanFactory,其次新建一個beanFactory,然后利用該factory裝載所有BeanDefinition

  其中,loadBeanDefinitions會交給子類做不同的實現(xiàn),比如AbstractXmlApplicationContext主要是通過xml讀??;AnnotationConfigWebApplicationContext的實現(xiàn)則會調(diào)用掃描器掃描類中的bean

解析Java的Spring框架的基本結(jié)構(gòu)

   3. 生成并注冊beanDefinition
  當(dāng)解析完xml配置以后,DefaultBeanDefinitionDocumentReader的parseDefaultElement方法會根據(jù)xml中的元素做對應(yīng)的處理。其中,遇到bean元素時會最終調(diào)用BeanDefinitionReaderUtils中的registerBeanDefinition方法,該方法傳入的參數(shù)為BeanDefinitionRegistry,實際上是回調(diào)了DefaultListableBeanFactory的registerBeanDefinition方法來注冊beanDefinition(DefaultListableBeanFactory實現(xiàn)了BeanDefinitionRegistry)。

   4. beanFactory后處理器

   beanFactory后處理器是spring提供出來的讓其子類靈活擴展的方式。spring中分為2個步驟:postProcessBeanFactory,invokeBeanFactoryPostProcessors。registerBeanPostProcessors則是實例化并調(diào)用所有的BeanPostProcessor,用來在bean初始化前和初始化后對bean做擴展。

   5. 設(shè)置消息,事件及監(jiān)聽器

  設(shè)置默認消息源為DelegatingMessageSource,如工廠里已經(jīng)有messageSource則使用該messageSource,事件多播器為SimpleApplicationEventMulticaster,如工廠里已經(jīng)有applicationEventMulticaster,則使用該applicationEventMulticaster,并注冊所有的應(yīng)用程序Listener以便能夠接收事件

  消息源:MessageSource是國際化資源文件的重要方法,spring在applicationContext就支持消息源。

  spring中提供了MessageSource的默認實現(xiàn),使用java.util.ResourceBundle來提取消息。spring通過配置一個特殊id為messageSource的bean并制定i18n的文件名,就能夠從ApplicationContext.getMessage()直接訪問message。如果在jsp中,還能通過spring:message這個tag訪問到message。

  事件:事件是比較重要的解耦機制,spring在核心ApplicationContext就引入了它,其原理比較簡單,一方面是事件產(chǎn)生方,能夠發(fā)送事件;一方面似乎事件監(jiān)聽方,能夠響應(yīng)事件。而具體實現(xiàn)基本上都是在產(chǎn)生方hold住一個事件監(jiān)聽者集合,并將所有監(jiān)聽方“注冊”(即加入)到這個事件監(jiān)聽者集合。

  spring中將ApplicationContext當(dāng)做事件產(chǎn)生方,使用applicationListeners作為監(jiān)聽者集合,applicationEventMulticaster用來做事件發(fā)布。

  事件發(fā)布的幾個步驟:

  訂閱:最初addApplicationListener將applicationListener加入監(jiān)聽者集合。

  發(fā)布:ApplicationContext繼承了ApplicationEventPublisher,因而實現(xiàn)了publishEvent,該方法首先會遍歷本applicationContext的applicationListeners集合,對每個listener調(diào)用onApplicationEvent,因此每個listener都會被通知到;這步完成后會對applicationContext的parent的所有applicationListeners做同樣的事件發(fā)布。

  事件發(fā)布非常常用,不僅我們自己的應(yīng)用可以使用這個事件發(fā)布,spring框架自身也在使用事件發(fā)布。下面是一些spring中事件的應(yīng)用:

  在finishRefresh中會發(fā)布ContextRefreshedEvent表明refresh結(jié)束借此通知listener。在ApplicationContext中start和stop方法會發(fā)布事件表示context開始或結(jié)束。
  johnson將spring的主框架與運行流程創(chuàng)造完畢之后,發(fā)覺spring中提供了許多靈活擴展的地方。于是johnson準備在第三日將這些靈活擴展的用法公布出來。

  1. BeanPostProcessor。BeanPostProcessor提供了bean創(chuàng)建完成后的擴展接口,當(dāng)你需要在bean創(chuàng)建完后對其做一定處理,則BeanPostProcessor是首選的方式。

  2. Aware。注入的bean需要了解其容器的某些部分,spring通過Aware完成回調(diào),如BeanNameAware,可以讓bean得知自己的名字, BeanFactoryAware可以讓bean了解到BeanFactory, ApplicationContextAware,可以讓bean操作ApplicationContext。通過這種方式,注入spring的bean能夠做更加廣泛的事情。

  對于BeanPostProcessor的擴展,spring自身有一個例子,即如何識別Aware bean的例子。Aware bean是比較特殊的bean,需要spring對其額外注入一些屬性,那么注入的過程spring會怎么做呢?實際上spring并沒有將他寫在核心的處理過程里面,而是放到了ApplicationContextAwareProcessor這個BeanPostProcessor,通過BeanPostProcessor的postProcessBeforeInitialization最終invokeAwareInterfaces以判斷該bean的類型并注入相應(yīng)的屬性。這種做法利用了BeanPostProcessor完成了另一個擴展用法,實在是高超。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
            new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
      }
      if (bean instanceof ResourceLoaderAware) {
        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
    }
  }

  關(guān)于Aware的用法則更多了,比如如下代碼能夠感知ApplicationContext,spring在創(chuàng)建完這個bean之后便會注入ApplicationContext,于是我們就可以使用該context完成事件發(fā)布。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class HelloBean implements ApplicationContextAware { 
  
  private ApplicationContext applicationContext; 
  private String helloWord = "Hello!World!"
  
  public void setApplicationContext(ApplicationContext context) { 
    this.applicationContext = context; 
  
  
  public void setHelloWord(String helloWord) { 
    this.helloWord = helloWord; 
  
  
  public String getHelloWord() { 
    applicationContext.publishEvent( 
        new PropertyGettedEvent("[" + helloWord + "] is getted")); 
    return helloWord; 
  

  3. BeanFactoryPostProcessor,這個PostProcessor通常是用來處理在BeanFactory創(chuàng)建后的擴展接口。一個例子如下,當(dāng)注入這個bean以后,它便會在BeanFactory創(chuàng)建完畢自動打印注入的bean數(shù)量:

?
1
2
3
4
5
6
7
8
9
public class BeanCounter implements BeanFactoryPostProcessor{
 
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
      throws BeansException {
    System.out.println(beanFactory.getBeanDefinitionCount());
  }
   
}

   4. FactoryBean。FactoryBean是一種特殊的bean,這種bean允許注入到spring容器并用其生成真正的bean,所以可以這樣定義,F(xiàn)actoryBean本身是一種bean,這種bean又有能夠提供bean的能力。下面從FactoryBean的調(diào)用開始,講到spring是如何使用這個bean的。
   要想?yún)^(qū)分普通bean和FactoryBean,spring也必須有判斷他們并特殊處理的過程,這個過程就在AbstractBeanFactory的getObjectForBeanInstance中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
 
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
      throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }
 
    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
      return beanInstance;
    }
 
    Object object = null;
    if (mbd == null) {
      object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      if (mbd == null && containsBeanDefinition(beanName)) {
        mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
  }

  可以看出來,如果是普通bean,就直接返回了,而如果是FactoryBean,最終調(diào)用會調(diào)用factory.getObject從而返回具體對象。如果將整個spring看做一個抽象工廠,生產(chǎn)抽象的bean時,則FactoryBean就是具體工廠,生產(chǎn)你需要的對象。
  spring中FactoryBean用法很多,舉個比較常見的例子,集成hibernate的sessionFactory時一般會注入LocalSessionFactoryBean,但是這個sessionFactory實際上不是普通的bean,可以簡單在配置文件中注入就能生產(chǎn),它有很多定制的部分,于是spring讓這個bean成為一個FactoryBean并控制其生產(chǎn)的對象。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 一区二区三区四区免费 | 国产成人高清在线观看 | 91看片在线免费观看 | 91精品国产综合久久婷婷香蕉 | 一级免费看片 | 在线亚洲综合 | 精品少妇v888av | 福利免费视频 | 国产精品久久久久久久不卡 | 天天操综 | 18欧美性xxxx极品hd | av在线免费观看国产 | 欧美日韩1区2区3区 黄片毛片一级 | 日韩欧美视频一区二区三区 | 夜夜夜精品视频 | 狠狠操人人干 | 日本黄色一级毛片 | 精品亚洲一区二区 | 免费亚洲视频在线观看 | 欧美一区二区三区成人精品 | 久久久成人一区二区免费影院 | 免费亚洲视频在线观看 | 色婷婷综合久久久久中文 | 国产午夜精品一区二区三区在线观看 | 国产精品久久久久久久久久10秀 | 精品成人一区二区三区 | 欧美一级免费高清 | 精品国产乱码久久久久久久 | 日韩精品一区二区在线 | 国产女厕一区二区三区在线视 | 久久男人视频 | 欧美色爱综合 | 欧美一级视频网站 | 高清做爰免费无遮网站挡 | 国产免费乱淫av | 九色 在线 | 国产亚洲欧美日韩在线观看不卡 | 免费a视频 | 免费午夜视频在线观看 | 91免费大片 | 免费a级毛片永久免费 |