程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 圖解Spring框架的設計理念與設計形式

圖解Spring框架的設計理念與設計形式

編輯:關於JAVA

圖解Spring框架的設計理念與設計形式。本站提示廣大學習愛好者:(圖解Spring框架的設計理念與設計形式)文章只能為提供參考,不一定能成為您想要的結果。以下是圖解Spring框架的設計理念與設計形式正文


本文重要分析Spring框架的作者設計Spring框架的骨骼架構的設計理念,有那幾個焦點組件?為何須要這些組件?它們又是若何聯合在一路組成Spring的骨骼架構?Spring的AOP特征又是若何應用這些基本的骨骼架構來任務的?Spring中又應用了那些設計形式來完成它的這類設計的?它的這類設計理念對我們今後的軟件設計有何啟發?本文將具體解答這些成績。

Spring的骨骼架構

Spring總共有十幾個組件,然則真正焦點的組件只要幾個,上面是Spring框架的整體架構圖:

圖1.Spring框架的整體架構圖

從上圖中可以看出Spring框架中的焦點組件只要三個:Core、Context和Beans。它們構建起了全部Spring的骨骼架構。沒有它們就弗成能有AOP、Web等下層的特征功效。上面也將重要從這三個組件動手剖析Spring。

Spring的設計理念

後面引見了Spring的三個焦點組件,假如再在它們三個當選出焦點的話,那就非Beans組件莫屬了,為什麼如許說,其實Spring就是面向Bean的編程(BOP,Bean Oriented Programming),Bean在Spring 中才是真實的配角。

Bean在Spring中感化就像Object對OOP的意義一樣,沒有對象的概念就像沒有面向對象編程,Spring中沒有Bean也就沒有Spring存在的意義。就像一次表演舞台都預備好了然則卻沒有演員一樣。為什 麼要Bean這類腳色Bean或許為什麼在Spring如斯主要,這由Spring框架的設計目的決議,Spring為什麼如斯風行,我們用Spring的緣由是甚麼,想一想你會發明本來Spring處理了一個異常症結的成績他可讓 你把對象之間的依附關系轉而用設置裝備擺設文件來治理,也就是他的依附注入機制。而這個注入關系在一個叫Ioc容器中治理,那Ioc容器中有又是甚麼就是被Bean包裹的對象。Spring恰是經由過程把對象包裝在 Bean中而到達對這些對象治理和一些列額定操作的目標。

它這類設計謀略完整相似於Java完成OOP的設計理念,固然了Java自己的設計要比Spring龐雜太多太多,然則都是構建一個數據構造,然後依據這個數據構造設計他的生計情況,並讓它在這個情況中 依照必定的紀律在一直的活動,在它們的一直活動中設計一系列與情況或許與其他個別完成信息交流。如許想往返過火想一想我們用到的其他框架都是年夜慨相似的設計理念。

焦點組件若何協同任務

後面說Bean是Spring中症結身分,那Context和Core又有何感化呢?後面吧Bean比作一場表演中的演員的話,那Context就是這場表演的舞台配景,而Core應當就是表演的道具了。只要他們在一路能力 具有能表演一場好戲的最根本的前提。固然有最根本的前提還不克不及使這場表演鋒芒畢露,還要他扮演的節目足夠的出色,這些節目就是Spring能供給的特點功效了。

我們曉得Bean包裝的是Object,而Object必定稀有據,若何給這些數據供給生計情況就是Context要處理的成績,對Context來講他就是要發明每一個Bean之間的關系,為它們樹立這類關系而且要保護好 這類關系。所以Context就是一個Bean關系的聚集,這個關系聚集又叫Ioc容器,一旦樹立起這個Ioc容器後Spring便可認為你任務了。那Core組件又有甚麼用武之地呢?其實Core就是發明、樹立和保護每 個Bean之間的關系所須要的一些列的對象,從這個角度看來,Core這個組件叫Util更能讓你懂得。

它們之間可以用下圖來表現:

圖2.三個組件關系

焦點組件詳解

這裡將具體引見每一個組件外部類的條理關系,和它們在運轉時的時序次序。我們在應用Spring是應當留意的處所。

Bean組件

後面曾經解釋了Bean組件對Spring的主要性,上面看看Bean這個組件式怎樣設計的。Bean組件在Spring的org.springframework.beans包下。這個包下的一切類重要處理了三件事:Bean的界說、Bean 的創立和對Bean的解析。對Spring的應用者來講獨一須要關懷的就是Bean的創立,其他兩個由Spring在外部幫你完成了,對你來講是通明的。

SpringBean的創立時典范的工場形式,他的頂級接口是BeanFactory,下圖是這個工場的繼續條理關系:

 

圖4.Bean工場的繼續關系

BeanFactory有三個子類:ListableBeanFactory、HierarchicalBeanFactory和Autowire Capable Bean Factory。然則從上圖中我們可以發明終究的默許完成類是DefaultListableBeanFactory,他實 現了一切的接口。那為什麼要界說這麼多條理的接口呢?查閱這些接口的源碼和解釋發明,每一個接口都有他應用的場所,它重要是為了辨別在Spring外部在操作進程中對象的傳遞和轉化進程中,對對象的 數據拜訪所做的限制。例如ListableBeanFactory接口表現這些Bean是可列表的,而HierarchicalBeanFactory表現的是這些Bean是有繼續關系的,也就是每一個Bean有能夠有父Bean。 AutowireCapableBeanFactory接口界說Bean的主動拆卸規矩。這四個接口配合界說了Bean的聚集、Bean之間的關系、和Bean行動。

Bean的界說重要有BeanDefinition描寫,以下圖解釋了這些類的條理關系:

圖5.Bean界說的類條理關系圖

Bean的界說就是完全的描寫了在Spring的設置裝備擺設文件中你界說的節點中一切的信息,包含各類子節點。當Spring勝利解析你界說的一個節點後,在Spring的外部他就被轉化 成BeanDefinition對象。今後一切的操作都是對這個對象完成的。

Bean的解析進程異常龐雜,功效被分的很細,由於這裡須要被擴大的處所許多,必需包管有足夠的靈巧性,以應對能夠的變更。Bean的解析重要就是對Spring設置裝備擺設文件的解析。這個解析進程重要經由過程 下圖中的類完成:

圖6.Bean的解析類

固然還有詳細對tag的解析這裡並沒有列出。

Context組件

Context在Spring的org.springframework.context包下,後面曾經講授了Context組件在Spring中的感化,他現實上就是給Spring供給一個運轉時的情況,用以保留各個對象的狀況。上面看一下這個 情況是若何構建的。

ApplicationContext是Context的頂級父類,他除能標識一個運用情況的根本信息外,他還繼續了五個接口,這五個接口重要是擴大了Context的功效。上面是Context的類構造圖:


圖7.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相干的類構造圖:

圖8.Resource相干的類構造圖

從上圖可以看出Resource接口封裝了各類能夠的資本類型,也就是對應用者來講屏障了文件類型的分歧。對資本的供給者來講,若何把資本包裝起來交給其別人用這也是一個成績,我們看到Resource 接口繼續了InputStreamSource接口,這個接口中有個getInputStream辦法,前往的是InputStream類。如許一切的資本都被可以經由過程InputStream這個類來獲得,所以也屏障了資本的供給者。別的還有一 個成績就是加載資本的成績,也就是資本的加載者要同一,從上圖中可以看出這個義務是由ResourceLoader接口完成,他屏障了一切的資本加載者的差別,只須要完成這個接口便可以加載一切的資本, 他的默許完成是DefaultResourceLoader。

上面看一下Context和Resource是若何樹立關系的?起首看一下他們的類關系圖:

圖9.Context和Resource的類關系圖

從上圖可以看出,Context是把資本的加載、解析和描寫任務拜托給了ResourcePatternResolver類來完成,他相當於一個接頭人,他把資本的加載、解析和資本的界說整合在一路便於其他組件應用。 Core組件中還有許多相似的方法。

Ioc容器若何任務

後面引見了Core組件、Bean組件和Context組件的構造與互相關系,上面這裡從應用者角度看一下他們是若何運轉的,和我們若何讓Spring完成各類功效,Spring究竟能有那些功效,這些功效是如 何得來的,上面引見。

若何創立BeanFactory工場

正如圖2描寫的那樣,Ioc容器現實上就是Context組件聯合其他兩個組件配合構建了一個Bean關系網,若何構建這個關系網?構建的進口就在AbstractApplicationContext類的refresh辦法中。這個方 法的代碼以下:

清單1.AbstractApplicationContext.refresh

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& nbsp;the context. 
 
      invokeBeanFactoryPostProcessors(beanFactory);  
 
      // Register bean processors that intercept bean crea tion. 
 
      registerBeanPostProcessors (beanFactory); 
 
      // Initialize message source for this context.  
 
      initMessageSource();  
 
      // Initialize event multicaster for this context.  
 
      initApplicationEventMulticaster();  
 
      // Initialize other special beans in specific contex t 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 dangl ing resources. 
 
      destroyBeans();  
 
      // Reset 'active' flag.  
 
      cancelRefresh(ex);  
 
      // Propagate exception to caller.  
 
      throw ex;  
 
    } 
 
  } 
 
} 
 

這個辦法就是構建全部Ioc容器進程的完全的代碼,懂得了外面的每行代碼根本上就懂得年夜部門Spring的道理和功效了。

這段代碼重要包括如許幾個步調:

◆構建BeanFactory,以便於發生所需的“演員”

◆注冊能夠感興致的事宜

◆創立Bean實例對象

◆觸發被監聽的事宜

上面就聯合代碼剖析這幾個進程。

第二三句就是在創立和設置裝備擺設BeanFactory。這裡是refresh也就是刷新設置裝備擺設,後面引見了Context有可更新的子類,這裡恰是完成這個功效,當BeanFactory已存在是就更新,假如沒有就新創立。上面是 更新BeanFactory的辦法代碼:

清單2. AbstractRefreshableApplicationContext. refreshBeanFactory

protected final void refreshBeanFactory() throws BeansException {  
 
  if (hasBeanFactory()) {  
 
    destroyBeans();  
 
    closeBeanFactory();  
 
  } 
 
  try { 
 
    DefaultListableBeanFactory beanFactory = createBeanFactory(); 
 
    beanFactory.setSerializationId(getId()); 
 
    customizeBeanFactory(beanFactory); 
 
    loadBeanDefinitions(beanFactory); 
 
    synchronized (this.beanFactoryMonitor) { 
 
      this.beanFactory = beanFactory;  
 
    } 
 
  } 
 
  catch (IOException ex) {  
 
    throw new ApplicationContextException(  
 
            "I/O error& nbsp;parsing bean definition source for " 
 
            + getDisplayName (), ex); 
 
  } 
 
}  

這個辦法完成了AbstractApplicationContext的籠統辦法refreshBeanFactory,這段代碼清晰的解釋了BeanFactory的創立進程。留意BeanFactory對象的類型的變更,前 面引見了他有許多子類,在甚麼情形下應用分歧的子類這異常症結。BeanFactory的原始對象是DefaultListableBeanFactory,這個異常症結,由於他設計到前面對這個對象的多種操作,上面看一下這個 類的繼續條理類圖:

圖10.DefaultListableBeanFactory類繼續關系圖

從這個圖中發明除BeanFactory相干的類外,還發明了與Bean的register相干。這在refreshBeanFactory辦法中有一行loadBeanDefinitions(beanFactory)將找到謎底,這個辦法將開端加載、解析 Bean的界說,也就是把用戶界說的數據構造轉化為Ioc容器中的特定命據構造。

這個進程可以用上面時序圖說明:

圖11.創立BeanFactory時序圖

Bean的解析和掛號流程時序圖以下:

圖12.解析和掛號Bean對象時序圖

創立好BeanFactory後,接下去添加一些Spring自己須要的一些對象類,這個操作在AbstractApplicationContext的prepareBeanFactory辦法完成。

AbstractApplicationContext中接上去的三行代碼對Spring的功效擴大性起了相當主要的感化。前兩行重要是讓你如今可以對曾經構建的BeanFactory的設置裝備擺設做修正,前面一行就是讓你可以對今後再 創立Bean的實例對象時添加一些自界說的操作。所以他們都是擴大了Spring的功效,所以我們要進修應用Spring必需對這一部門弄清晰。

個中在invokeBeanFactoryPostProcessors辦法中重要是獲得完成BeanFactoryPostProcessor接口的子類。並履行它的postProcessBeanFactory辦法,這個辦法的聲明以下:

清單3.BeanFactoryPostProcessor.postProcessBeanFactory

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)  
 
  throws BeansException;
 

它的參數是beanFactory,解釋可以對beanFactory做修正,這裡留意這個beanFactory是ConfigurableListableBeanFactory類型的,這也印證了後面引見的分歧BeanFactory所應用的場所分歧,這裡 只能是可設置裝備擺設的BeanFactory,避免一些數據被用戶隨便修正。

registerBeanPostProcessors辦法也是可以獲得用戶界說的完成了BeanPostProcessor接口的子類,並履行把它們注冊到BeanFactory對象中的beanPostProcessors變量中。BeanPostProcessor中聲明 了兩個辦法:postProcessBeforeInitialization、postProcessAfterInitialization分離用於在Bean對象初始化時履行。可以履行用戶自界說的操作。

前面的幾行代碼是初始化監聽事宜和對體系的其他監聽者的注冊,監聽者必需是ApplicationListener的子類。

若何創立Bean實例並構建Bean的關系網

上面就是Bean的實例化代碼,是從finishBeanFactoryInitialization辦法開端的。

清單4.AbstractApplicationContext.finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization( 
 
    ConfigurableListableBeanFactory beanFactory) { 
 
  
 
  // Stop using the temporary ClassLoader for type matching.  
 
  beanFactory.setTempClassLoader(null);  
 
  
 
  // Allow for caching all bean definition metadata, not expecting further changes . 
 
  beanFactory.freezeConfiguration();  
 
  
 
  // Instantiate all remaining (non-lazy-init) singletons. 
 
  beanFactory.preInstantiateSingletons(); 
 
}  
 

從下面代碼中可以發明Bean的實例化是在BeanFactory中產生的。preInstantiateSingletons辦法的代碼以下:

清單5.DefaultListableBeanFactory.preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {  
 
  if (this.logger.isInfoEnabled()) {  
 
    this.logger.info("Pre- instantiating singletons in " + this); 
 
  }  
 
  synchronized (this.beanDefinitionMap) {  
 
    for  (String beanName : this.beanDefinitionNames) { 
 
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);  
 
      if (!bd.isAbstract()  && bd.isSingleton() 
 
        && !bd.isLazyInit()) {  
 
        if  (isFactoryBean(beanName)) { 
 
          final FactoryBean factory = 
 
            (FactoryBean)  getBean(FACTORY_BEAN_PREFIX+ beanName); 
 
          boolean isEagerInit;  
 
          if (System.getSecurityManager()  != null 
 
            &&  ;factory instanceof SmartFactoryBean) { 
 
            isEagerInit = AccessController.doPrivileged(  
 
             &nb sp; new PrivilegedAction<Boolean>() {  
 
             &nb sp; public Boolean run() { 
 
 return ((SmartFactoryBean)  factory).isEagerInit(); 
 
             &nb sp; } 
 
            }, getAcce ssControlContext()); 
 
          }  
 
          else {  
 
            isEagerInit = factory instanceof SmartFactoryBean  
 
             &nb sp; && ((SmartFactoryBean) factory).isEagerInit(); 
 
          }  
 
          if (isEagerInit) {  
 
            getBean (beanName); 
 
          }  
 
        }  
 
        else {  
 
          getBean(beanName);  
 
        }  
 
      }  
 
    } 
 
  } 
 
} 
 

這裡湧現了一個異常主要的Bean——FactoryBean,可以說Spring一年夜半的擴大的功效都與這個Bean有關,這是個特別的Bean他是個工場Bean,可以發生Bean的Bean,這裡的發生Bean是指 Bean的實例,假如一個類繼續FactoryBean用戶可以本身界說發生實例對象的辦法只需完成他的getObject辦法。但是在Spring外部這個Bean的實例對象是FactoryBean,經由過程挪用這個對象的getObject方 法就可以獲得用戶自界說發生的對象,從而為Spring供給了很好的擴大性。Spring獲得FactoryBean自己的對象是在後面加上&來完成的。

若何創立Bean的實例對象和若何構建Bean實例對象之間的聯系關系關系式Spring中的一個焦點症結,上面是這個進程的流程圖。


圖13.Bean實例創立流程圖

假如是通俗的Bean就直接創立他的實例,是經由過程挪用getBean辦法。上面是創立Bean實例的時序圖:

圖14.Bean實例創立時序圖

還有一個異常主要的部門就是樹立Bean對象實例之間的關系,這也是Spring框架的焦點競爭力,什麼時候、若何樹立他們之間的關系請看上面的時序圖:

圖15.Bean對象關系樹立

Ioc容器的擴大點

如今還有一個成績就是若何讓這些Bean對象有必定的擴大性,就是可以參加用戶的一些操作。那末有哪些擴大點呢?Spring又是若何挪用到這些擴大點的?

對Spring的Ioc容器來講,重要有這麼幾個。BeanFactoryPostProcessor,BeanPostProcessor。他們分離是在構建BeanFactory和構建Bean對象時挪用。還有就是InitializingBean和DisposableBean 他們分離是在Bean實例創立和燒毀時被挪用。用戶可以完成這些接口中界說的辦法,Spring就會在恰當的時刻挪用他們。還有一個是FactoryBean他是個特別的Bean,這個Bean可以被用戶更多的掌握。

這些擴大點平日也是我們應用Spring來完成我們特定義務的處所,若何精曉Spring就看你有無控制好Spring有哪些擴大點,而且若何應用他們,要曉得若何應用他們就必需懂得他們內涵的機理。可 以用上面一個比方來說明。

我們把Ioc容器比作一個箱子,這個箱子裡有若干個球的模型,可以用這些模型來造許多種分歧的球,還有一個造這些球模的機械,這個機械可以發生球模。那末他們的對應關系就是BeanFactory就是 誰人造球模的機械,球模就是Bean,而球模造出來的球就是Bean的實例。那後面所說的幾個擴大點又在甚麼處所呢?BeanFactoryPostProcessor對應到當造球模被造出來時,你將無機會可以對其做出設 當的修改,也就是他可以幫你修正球模。而InitializingBean和DisposableBean是在球模造球的開端和停止階段,你可以完成一些准備和收尾任務。BeanPostProcessor便可以讓你對球模造出來的球做出 恰當的修改。最初還有一個FactoryBean,它可是一個奇異的球模。這個球模不是事後就定型了,而是由你來給他肯定它的外形,既然你可以肯定這個球模子的外形,固然他造出來的球確定就是你想要的 球了,如許在這個箱子裡尼可以發明一切你想要的球

Ioc容器若何為我所用

後面的引見了Spring容器的構建進程,那Spring能為我們做甚麼,Spring的Ioc容器又能做甚麼呢?我們應用Spring必需要起首構建Ioc容器,沒有它Spring沒法任務,ApplicatonContext.xml就是Ioc 容器的默許設置裝備擺設文件,Spring的一切特征功效都是基於這個Ioc容器任務的,好比前面要引見的AOP。

Ioc它現實上就是為你構建了一個魔方,Spring為你搭好了骨骼架構,這個魔方究竟能變出甚麼好的器械出來,這必需要有你的介入。那我們怎樣介入?這就是後面說的要懂得Spring中那有些擴大點 ,我們經由過程完成那些擴大點來轉變Spring的通用行動。至於若何完成擴大點來獲得我們想要的特性成果,Spring中有許多例子,個中AOP的完成就是Spring自己完成了其擴大點來到達了它想要的特征功效 ,可以拿來參考。

Spring中AOP特征詳解

靜態署理的完成道理

要懂得Spring的AOP就必需先懂得的靜態署理的道理,由於AOP就是基於靜態署理完成的。靜態署理還要從JDK自己說起。

在Jdk的java.lang.reflect包下有個Proxy類,它恰是結構署理類的進口。這個類的構造入下:

圖16.Proxy類構造

從上圖發明最初面四個是私有辦法。而最初一個辦法newProxyInstance就是創立署理對象的辦法。這個辦法的源碼以下:

清單6.Proxy.newProxyInstance

public static Object newProxyInstance(ClassLoader loader,  
 
  Class> [] interfaces, 
 
  InvocationHandler h)  
 
  throws IllegalArgumentException {  
 
   
 
    if (h == null) {  
 
    throw new NullPointerException();  
 
  } 
 
  Class cl = getProxyClass (loader, interfaces); 
 
  try {  
 
    Constructor cons = cl.getConstructor(constructorParams);  
 
    return (Object) cons.newInstance(new Object[]  { h }); 
 
  } catch (NoSuchMethodException e) {  
 
    throw new InternalError(e.toString());  
 
  } catch (IllegalAccessException e) {  
 
    throw new InternalError(e.toString());  
 
  } catch (InstantiationException e) {  
 
    throw new InternalError(e.toString());  
 
  } catch (InvocationTargetException e) {  
 
    throw new InternalError(e.toString());  
 
  } 
 
}  
 

這個辦法須要三個參數:ClassLoader,用於加載署理類的Loader類,平日這個Loader和被署理的類是統一個Loader類。Interfaces,是要被署理的那些那些接口。InvocationHandler,就是用於履行 除被署理接口中辦法以外的用戶自界說的操作,他也是用戶須要署理的終究目標。用戶挪用目的辦法都被署理到InvocationHandler類中界說的獨一辦法invoke中。這在前面再詳解。

上面照樣看看Proxy若何發生署理類的進程,他結構出來的署理類究竟是甚麼模樣?上面揭曉啦。

圖17.創立署理對象時序圖

其實從上圖中可以發明正在結構署理類的是在ProxyGenerator的generateProxyClass的辦法中。ProxyGenerator類在sun.misc包下,感興致的話可以看看他的源碼。

假設有如許一個接口,以下:

清單7.SimpleProxy類

public interface SimpleProxy { 
 
  
 
  public void simpleMethod1();  
 
     
 
  public void simpleMethod2(); 
 
   
 
} 
 

署理來生成的類構造以下:

清單 8.$Proxy2類

public class $Proxy2 extends java.lang.reflect.Proxy implements SimpleProxy{  
 
  java.lang.reflect.Method m0;  
 
  java.lang.reflect.Method m1; 
 
  java.lang.reflect.Method m2; 
 
  java.lang.reflect.Method m3; 
 
  java.lang.reflect.Method m4; 
 
   
 
  int hashCode(); 
 
  boolean equals(java.lang.Object); 
 
  java.lang.String toString(); 
 
  void simpleMethod1(); 
 
  void simpleMethod2(); 
 
}  
 

這個類中的辦法外面將會是挪用InvocationHandler的invoke辦法,而每一個辦法也將對應一個屬性變量,這個屬性變量m也將傳給invoke辦法中的Method參數。全部署理就是如許完成的。

SpringAOP若何完成

早年面署理的道理我們曉得,署理的目標是挪用目的辦法時我們可以轉而履行InvocationHandler類的invoke辦法,所以若何在InvocationHandler上做文章就是Spring完成Aop的症結地點。

Spring的Aop完成是遵照Aop同盟的商定。同時Spring又擴大了它,增長了如Pointcut、Advisor等一些接口使得加倍靈巧。

上面是Jdk靜態署理的類圖:

圖18.Jdk靜態署理的類圖

上圖清晰的顯示了Spring援用了Aop Alliance界說的接口。權且不評論辯論Spring若何擴大Aop Alliance,先看看Spring若何完成署理類的,要完成署理類在Spring的設置裝備擺設文件中平日是如許定一個Bean的 ,以下:

清單9.設置裝備擺設署理類Bean

<bean id="testBeanSingleton" 
 
  class="org.springframework.aop.framework.ProxyFactoryBean"> 
 
  <property name="proxyInterfaces"> 
 
    <value> 
 
      org.springframework.aop.framework.PrototypeTargetTests$TestBean  
 
    value> 
 
  property> 
 
  <property name="target"><ref local="testBeanTarget">ref> property> 
 
  <property name="singleton"><value>truevalue>property> 
 
  <property name="interceptorNames"> 
 
    <list> 
 
      <value>testInterceptorvalue> 
 
      <value>testInterceptor2value> 
 
    list> 
 
  property> 
 
bean> 
 

設置裝備擺設上看到要設置被署理的接口,和接口的完成類也就是目的類,和攔阻器也就在履行目的辦法之前被挪用,這裡Spring中界說的各類各樣的攔阻器,可以選擇應用。

上面看看Spring若何完成了署理和是若何挪用攔阻器的。

後面提到Spring Aop也是完成其本身的擴大點來完成這個特征的,從這個署理類可以看出它恰是繼續了Factory Bean的ProxyFactoryBean,FactoryBean之所以特殊就在它可讓你自界說對象的創立 辦法。固然署理對象要經由過程Proxy類來靜態生成。

上面是Spring創立的署理對象的時序圖:

圖19.Spring署理對象的發生

Spring創立了署理對象後,當你挪用目的對象上的辦法時,將都邑被署理到InvocationHandler類的invoke辦法中履行,這在後面曾經說明。在這裡JdkDynamicAopProxy類完成了InvocationHandler接 口。

上面再看看Spring是若何挪用攔阻器的,上面是這個進程的時序圖:

圖20.Spring挪用攔阻器

以上所說的都是Jdk靜態署理,Spring還支撐一種CGLIB類署理,感興致本身看吧。

Spring中設計形式剖析

Spring中應用的設計形式也許多,好比工場形式、單例形式、模版形式等,在《Webx框架的體系架構與設計形式》、《Tomcat的體系架構與形式設計剖析》曾經有引見,這裡就不贅述了。這裡重要介 紹署理形式和戰略形式。

署理形式

署理形式道理

署理形式就是給某一個對象創立一個署理對象,而由這個署理對象掌握對原對象的援用,而創立這個署理對象就是可以在挪用原對象是可以增長一些額定的操作。上面是署理形式的構造:

圖21.署理形式的構造

Subject:籠統主題,它是署理對象的真實對象要完成的接口,固然這可所以多個接口構成。

ProxySubject:署理類除完成籠統主題界說的接口外,還必需持有所署理對象的援用

RealSubject:被署理的類,是目的對象。

Spring中若何完成署理形式

Spring Aop中Jdk靜態署理就是應用署理形式技巧完成的。在Spring中除完成被署理對象的接口外,還會有org.springframework.aop.SpringProxy和org.springframework.aop.framework.Advised 兩個接口。Spring中應用署理形式的構造圖以下:

圖22.Spring中應用署理形式的構造圖

$Proxy就是創立的署理對象,而Subject是籠統主題,署理對象是經由過程InvocationHandler來持有對目的對象的援用的。

Spring中一個真實的署理對象構造以下:

清單10署理對象$Proxy4

public class $Proxy4 extends java.lang.reflect.Proxy implements  
 
  org.springframework.aop.framework.PrototypeTargetTests$TestBean  
 
    org.springframework.aop.SpringProxy  
 
    org.springframework.aop.framework.Advised  
 
{ 
 
  java.lang.reflect.Method m16; 
 
  java.lang.reflect.Method m9; 
 
  java.lang.reflect.Method m25; 
 
  java.lang.reflect.Method m5; 
 
  java.lang.reflect.Method m2; 
 
  java.lang.reflect.Method m23; 
 
  java.lang.reflect.Method m18; 
 
  java.lang.reflect.Method m26; 
 
  java.lang.reflect.Method m6; 
 
  java.lang.reflect.Method m28; 
 
  java.lang.reflect.Method m14; 
 
  java.lang.reflect.Method m12; 
 
  java.lang.reflect.Method m27; 
 
  java.lang.reflect.Method m11; 
 
  java.lang.reflect.Method m22; 
 
  java.lang.reflect.Method m3; 
 
  java.lang.reflect.Method m8; 
 
  java.lang.reflect.Method m4; 
 
  java.lang.reflect.Method m19; 
 
  java.lang.reflect.Method m7; 
 
  java.lang.reflect.Method m15; 
 
  java.lang.reflect.Method m20; 
 
  java.lang.reflect.Method m10; 
 
  java.lang.reflect.Method m1; 
 
  java.lang.reflect.Method m17; 
 
  java.lang.reflect.Method m21; 
 
  java.lang.reflect.Method m0; 
 
  java.lang.reflect.Method m13; 
 
  java.lang.reflect.Method m24; 
 
   
 
  int hashCode(); 
 
  int indexOf(org.springframework.aop.Advisor); 
 
  int indexOf(org.aopalliance.aop.Advice); 
 
  boolean equals(java.lang.Object); 
 
  java.lang.String toString(); 
 
  void sayhello(); 
 
  void doSomething(); 
 
  void doSomething2(); 
 
  java.lang.Class getProxiedInterfaces(); 
 
  java.lang.Class getTargetClass(); 
 
  boolean isProxyTargetClass(); 
 
  org.springframework.aop.Advisor; getAdvisors(); 
 
  void addAdvisor(int, org.springframework.aop.Advisor) 
 
        throws org.springframework.aop.framework.AopConfigException;  
 
  void addAdvisor(org.springframework.aop.Advisor)  
 
        throws org.springframework.aop.framework.AopConfigException;  
 
  void setTargetSource(org.springframework.aop.TargetSource);  
 
  org.springframework.aop.TargetSource getTargetSource();  
 
  void setPreFiltered(boolean); 
 
  boolean isPreFiltered(); 
 
  boolean isInterfaceProxied(java.lang.Class); 
 
  boolean removeAdvisor(org.springframework.aop.Advisor); 
 
  void removeAdvisor(int)throws org.springframework.aop.framework.AopConfigException;  
 
  boolean replaceAdvisor(org.springframework.aop.Advisor,  
 
        org.springframework.aop.Advisor)  
 
        throws org.springframework.aop.framework.AopConfigException;  
 
  void addAdvice(org.aopalliance.aop.Advice)  
 
        throws org.springframework.aop.framework.AopConfigException;  
 
  void addAdvice(int, org.aopalliance.aop.Advice)  
 
        throws org.springframework.aop.framework.AopConfigException;  
 
  boolean removeAdvice(org.aopalliance.aop.Advice);  
 
  java.lang.String toProxyConfigString();  
 
  boolean isFrozen(); 
 
  void setExposeProxy(boolean); 
 
  boolean isExposeProxy(); 
 
}  
 

戰略形式

戰略形式道理

戰略形式望文生義就是做某事的戰略,這在編程上平日是指完成某個操作能夠有多種辦法,這些辦法各有所長,能夠有分歧的順應的場所,但是這些操作辦法都有能夠用到。各一個操作辦法都看成一 個完成戰略,應用者能夠依據須要選擇適合的戰略。

上面是戰略形式的構造:


圖23.戰略形式的構造

Context:應用分歧戰略的情況,它可以依據本身的前提選擇分歧的戰略完成類來完成所要的操作。它持有一個戰略實例的援用。創立詳細戰略對象的辦法也能夠由他完成。

◆Strategy:籠統戰略,界說每一個戰略都要完成的戰略辦法

◆ConcreteStrategy:詳細戰略完成類,完成籠統戰略中界說的戰略辦法

◆Spring中戰略形式的完成

◆Spring中戰略形式應用有多個處所,如Bean界說對象的創立和署理對象的創立等。這裡重要看一下署理對象創立的戰略形式的完成。

後面曾經懂得Spring的署理方法有兩個Jdk靜態署理和CGLIB署理。這兩個署理方法的應用恰是應用了戰略形式。它的構造圖以下所示:

圖24.Spring中戰略形式構造圖

在下面構造圖中與尺度的戰略形式構造略微有點分歧,這裡籠統戰略是AopProxy接口,Cglib2AopProxy和JdkDynamicAopProxy分離代表兩種戰略的完成方法,ProxyFactoryBean就是代表Context腳色 ,它依據前提選擇應用Jdk署理方法照樣CGLIB方法,而別的三個類重要是來擔任創立詳細戰略對象,ProxyFactoryBean是經由過程依附的辦法來聯系關系詳細戰略對象的,它是經由過程挪用戰略對象的getProxy (ClassLoaderclassLoader)辦法來完成操作。

總結

本文經由過程從Spring的幾個焦點組件動手,試圖找出構建Spring框架的骨骼架構,進而剖析Spring在設計的一些設計理念,能否從中找出一些好的設計思惟,對我們今後法式設計能供給一些思緒。接著 再具體剖析了Spring中是若何完成這些理念的,和在設計形式上是若何應用的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved