自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring核心組件原理解析

開發(fā) 架構
任何實際的應用程序都是由很多組件組成的,每個組件負責整個應用功能的一部分,這些組件需要與其他的應用元素進行協(xié)調以完成自己的任務。

盡管希臘哲學家赫拉克利特(Heraclitus)并不作為一名軟件開發(fā)人員而聞名,但他似乎深諳此道。他的一句話經常被引用:“唯一不變的就是變化”,這句話抓住了軟件開發(fā)的真諦。

我們現(xiàn)在開發(fā)應用的方式和1年前、5年前、10年前都是不同的,更別提15年前了,當時RodJohnson的圖書 Expert One-on-One J2EE Design and Development 介紹了Spring框架的初始形態(tài)。當時,最常見的應用形式是基于瀏覽器的Web應用,后端由關系型數(shù)據庫作為支撐。盡管這種形式的開發(fā)依然有它的價值,Spring也為這種應用提供了良好的支持,但是我們現(xiàn)在感興趣的還包括如何開發(fā)面向云的由微服務組成的應用,這些應用會將數(shù)據保存到各種類型的數(shù)據庫中。

另外一個嶄新的關注點是反應式編程,它致力于通過非阻塞操作提供更好的擴展性并提升性能。隨著軟件開發(fā)的發(fā)展,Spring框架也在不斷變化,以解決現(xiàn)代應用開發(fā)中的問題,其中就包括微服務和反應式編程。Spring還通過引入Spring Boot簡化自己的開發(fā)模型。

Spring 的核心

任何實際的應用程序都是由很多組件組成的,每個組件負責整個應用功能的一部分,這些組件需要與其他的應用元素進行協(xié)調以完成自己的任務。當應用程序運行時,需要以某種方式創(chuàng)建并引入這些組件。

Spring Framework 總共有十幾個組件,但真正核心的組件只有三個:Spring Core,Spring Context 和 Spring Bean,它們奠定了 Spring 的基礎并撐起了 Spring 的框架結構。Spring 的其它功能特性例如 Web、AOP、JDBC 等都是在其基礎上發(fā)展實現(xiàn)的。

Spring之中最重要的當屬Bean了,Spring實際上就是面向Bean的編程,Bean對于Spring的意義就好比Object對于OOP的意義一樣。那么,三個核心組件之間是如何協(xié)同工作的呢?如果把Bean比作一場演出中的演員,那么Context就是這場演出的舞臺,Core就是演出的道具,至于演出的節(jié)目,就是Spring的一系列特色功能了。

我們知道Bean包裹的是Object,而Object中必然有數(shù)據,Context就是給這些數(shù)據提供生存環(huán)境,發(fā)現(xiàn)每個Bean之間的關系,為他們建立并維護好這種關系。這樣來說,Context就是一個Bean關系的集合,這個關系集合就是我們所說的IOC容器。那么Core又有什么作用呢?Core就是發(fā)現(xiàn)、建立和維護每個Bean之間的關系所需的一系列工具,就是我們經常說的Util。

Bean 組件

Bean組件在Spring的org.springframework.beans包下,主要完成了Bean的創(chuàng)建、Bean的定義以及Bean的解析三件事。

SpringBean的創(chuàng)建是典型的工廠模式,其工廠的繼承層次關系如圖所示:

Spring 使用工廠模式來管理程序中使用的對象(Bean),Bean 工廠最上層的接口為 BeanFactory,簡單來看,工廠就是根據需要返回相應的 Bean 實例。 

  1. public interface BeanFactory {  
  2.     //...          
  3.     Object getBean(String name);  

在工廠模式中,在工廠的實現(xiàn)類中生成 Bean 返回給調用客戶端,這就要求客戶端提供生成自己所需類實例的工廠類,增加客戶負擔。Spring 結合控制反轉和依賴注入為客戶端提供所需的實例,簡化了客戶端的操作。具體的實現(xiàn)方式大致如下。 

  1. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory  
  2.         implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {  
  3.     /** Map of bean definition objects, keyed by bean name */  
  4.     private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition> 
  5.     public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){       
  6.         //...  
  7.     }  

beanDefinitionMap 作為具體的 Bean 容器,Spring 創(chuàng)建的對象實例保存其中??蛻舳诵枰獣r,使用工廠的 getBean 方法去試圖得到相應的實例,如果實例已存在,則返回該實例;如果實例不存在,則首先產生相應實例并通過 registerBeanDefinition 方法將其保存在 beanDefinitionMap 中(Lazy Initialization),然后返回該實例給客戶端。

Spring Bean 工廠的繼承關系

beanDefinitionMap 并不直接保存實例本身,而是將實例封裝在 BeanDefinition 對象后進行保存。BeanDefinition 包含了實例的所有信息,其簡化版的定義如下。 

  1. public class BeanDefinition {  
  2.     private Object bean;  
  3.     private Class<?> beanClass;  
  4.     private String beanClassName;  
  5.     // Bean 屬性字段的初始化值  
  6.     private BeanPropertyValues beanPropertyValues;  
  7.     //...  

Spring Bean 工廠生產 Bean 時

  1.  先將實例的類型參數(shù)保存到 beanClass 和 beanClassName,將需要初始化的字段名和值保存到 beanPropertyValues 中,這個過程 Spring 通過控制反轉來實現(xiàn),本文第二小節(jié)將予以簡要說明
  2.  生成 bean 實例,并利用反射機制將需要初始化的字段值寫入 bean 實例,將實例保存在 bean 中,完成 BeanDefinition 的構建。 

       假設我們已經完成了步驟 1) 的操作,之后的過程用代碼表述如下所示。 

  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){  
  2.     //生成 bean 實例,并完成初始化  
  3.     Object bean = createBean(beanDefinition);  
  4.     //將 bean 實例保存在 beanDefinition 中  
  5.     beanDefinition.setBean(bean);  
  6.     //將 beanDefinition 實例保存在 Spring 容器中  
  7.     beanDefinitionMap.put(beanName, beanDefinition);  
  8.  
  9. protected Object createBean(BeanDefinition beanDefinition) {  
  10.     try{  
  11.         Object bean = beanDefinition.getBeanClass().newInstance();  
  12.         try {  
  13.             setBeanPropertyValues(bean, beanDefinition);  
  14.         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.         return bean;  
  18.     }catch(InstantiationException e){  
  19.         e.printStackTrace();  
  20.     }catch(IllegalAccessException e){  
  21.         e.printStackTrace();  
  22.     }  
  23.     return null;  
  24.  
  25. protected void setBeanPropertyValues(Object bean, BeanDefinition beanDefinition) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{ 
  26.      for(PropertyValue pv : beanDefinition.getBeanPropertyValues().getBeanPropertyValues()){  
  27.         Field beanbeanFiled = bean.getClass().getDeclaredField(pv.getName());  
  28.         beanFiled.setAccessible(true);  
  29.         beanFiled.set(bean, pv.getValue());  
  30.     }  

Context 組件

前面說到,Context組件的作用是給Spring提供一個運行時的環(huán)境,用以保存各個對象的狀態(tài),我們來看一下與Context相關的類結構圖。

從圖中可以看出,Context類結構的頂級父類是ApplicationContext,它除了能標識一個應用環(huán)境的基本信息以外,還繼承了5個接口,這5個接口主要是擴展了Context的功能。ApplicationContext的子類主要包含兩個方向,圖中已作說明。再往下就是構建Context的文件類型,接著就是訪問Context的方式。

一般地,傳統(tǒng)的程序設計中,無論是使用工廠創(chuàng)建實例,或是直接創(chuàng)建實例,實例調用者都要先主動創(chuàng)建實例,而后才能使用??刂品崔D(Inverse of Control) 將實例的創(chuàng)建過程交由容器實現(xiàn),調用者將控制權交出,是所謂控制反轉。

依賴注入(Dependence Injection) 在控制反轉的基礎上更進一步。如果沒有依賴注入,容器創(chuàng)建實例并保存后,調用者需要使用 getBean(String beanName) 才能獲取到實例。使用依賴注入時,容器會將 Bean 實例自動注入到完成相應配置的調用者,供其進一步使用。

Context 組件借助上述的控制反轉和依賴注入,協(xié)助實現(xiàn)了 Spring 的 Ioc 容器。下面我們以一個 Service 類作為所需的 Bean 實例進行說明。實際應用中,我們會需要 Spring 管理很多 Bean 實例。 

  1. public class SampleService {  
  2.     private String service;  
  3.         public String getService() {  
  4.         return service;  
  5.     }  
  6.     public void setService(String service) {  
  7.         this.service= service;  
  8.     }  

在程序運行過程中,需要一個 SampleService ,我們不讓調用者 new 一個實例,而是在配置文件中表明該 SampleService 的實例交由 Spring 容器進行管理,并指定其初始化參數(shù)。配置文件即資源,其內容如下。 

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.     <bean name="sampleService " class="com.service.SampleService ">  
  4.         <property name="service" value="This is a service"></property>  
  5.     </bean>  
  6. </beans> 

Spring Core 組件提供 ResourceLoader 接口,便于讀入 xml 文件或其他資源文件。其核心功能代碼應該提供如下方法。 

  1. public class ResourceLoader {  
  2.     public Resource getResource(String location){  
  3.         URL resource = this.getClass().getClassLoader().getResource(location);  
  4.         return new UrlResource(resource);  
  5.     }  
  6.  
  7. // UrlResource 的功能代碼  
  8. public class UrlResource implements Resource {  
  9.     private final URL url;  
  10.     public UrlResource(URL url){  
  11.         this.url = url;  
  12.     }  
  13.     @Override  
  14.     public InputStream getInputStream() throws IOException {  
  15.         URLConnection urlurlConnection = url.openConnection();  
  16.         urlConnection.connect();  
  17.         return urlConnection.getInputStream();  
  18.     }  

即加載資源文件,并以數(shù)據流的形式返回。Context 根據資源中的定義,生成相應的 bean 并保存在容器中,bean 的名字是 sampleService ,供程序進一步使用。這樣就完成了控制反轉的工作。接下來就需要把 sampleService 注入到需要使用它的地方,亦即完成依賴注入操作。

現(xiàn)在假設 SampleController 中使用 SampleService 的對象,Spring 提供三種依賴注入的方式,構造器注入、setter 注入和注解注入。 

  1. public class SampleController {  
  2.     /**  
  3.      * 3\. 注解注入  
  4.     **/  
  5.     /* @Autowired */  
  6.     private SampleService sampleService;  
  7.     /**  
  8.      * 1\. 構造器注入  
  9.     **/  
  10.     public SampleController(SampleService sampleService){  
  11.         this.sampleService = sampleService;  
  12.     }  
  13.     //無參構造函數(shù)  
  14.     public SampleController(){}  
  15.     // 類的核心功能  
  16.     public void process(){  
  17.         System.out.println(sampleService.getService());  
  18.     }  
  19.     /**  
  20.      * 2\. setter 注入  
  21.     **/  
  22.     /*public void setService(SampleService service) {  
  23.         this.service= service;  
  24.     }*/  

三種注入方式在配置文件中對應不同的配置方式,在前面 xml 文件的基礎上,我們可以分別實現(xiàn)這三種注入方式。需要注意的是,這里 SampleController 也是使用 Spring 的 Ioc 容器生成管理的。 

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.     <bean name="sampleService " class="com.service.SampleService ">  
  4.         <property name="service" value="This is a service"></property>  
  5.     </bean>  
  6. <!-- 1\. 構造器注入方式為SampleContorller 的 bean 注入 SampleService -->  
  7.     <bean name="sampleContorller" class="com.controller.SampleContorller">  
  8.         <!-- index 是構造方法中相應參數(shù)的順序 -->  
  9.         <constructor-arg index="0" ref="sampleService"></constructor-arg>  
  10.     </bean>  
  11. <!-- 2\. setter 注入方式為SampleContorller 的 bean 注入 SampleService -->  
  12. <!--  
  13.     <bean name="sampleContorller" class="com.controller.SampleContorller">  
  14.         <property name="sampleService " ref="sampleService"></property>  
  15.     </bean>  
  16. -->  
  17. <!-- 3\. 注解注入方式為SampleContorller 的 bean 注入 SampleService -->  
  18. <!--  
  19.     <bean name="sampleContorller" class="com.controller.SampleContorller">  
  20.     <!-- 不需要配置,Spring 自動按照類型注入相應的 bean -->  
  21.     </bean>  
  22. -->  
  23. </beans> 

Core組件

Core組件一個重要的組成部分就是定義了資源的訪問方式。Core組價把所有的資源都抽象成一個接口,這樣,對于資源使用者來說,不需要考慮文件的類型。對資源提供者來說,也不需要考慮如何將資源包裝起來交給別人使用(Core組件內所有的資源都可以通過InputStream類來獲取)。另外,Core組件內資源的加載都是由ResourceLoader接口完成的,只要實現(xiàn)這個接口就可以加載所有的資源。

那么,Context和Resource是如何建立關系的呢?通過前面Context的介紹我們知道,Context組件里面的類或者接口最終都實現(xiàn)了ResourcePatternResolver接口,ResourcePatternResolver接口的作用就是加載、解析和描述資源。這個接口相當于Resource里面的一個接頭人,它把Resource里的資源加載、解析和定義整合到一起,便于其他組件使用。

前面介紹了三大核心組件的結構與相互關系,那么,這三大組件是如何讓Spring完成諸如IOC和AOP等各種功能的呢?敬請期待下一篇文章! 

 

責任編輯:龐桂玉 來源: JAVA高級架構
相關推薦

2021-07-12 09:45:36

NameServer 核心Conusmer

2025-03-07 10:23:46

2022-01-05 08:53:13

Spring原理分析MVC

2025-04-03 00:20:00

2021-05-14 06:15:48

SpringAware接口

2023-02-28 09:07:18

ChatGPTAI

2023-02-09 08:01:12

核心組件非阻塞

2019-12-06 10:59:20

JavaScript運行引擎

2021-01-12 14:46:34

Kubernetes開發(fā)存儲

2021-07-05 07:51:43

JVM底層Python

2023-12-26 08:08:02

Spring事務MySQL

2022-03-15 09:31:17

ESLint工作原理前端

2022-11-04 08:39:46

SpringWebFlux

2010-05-27 15:20:29

移動IPv6技術

2023-08-11 07:44:40

TCP滑動窗口數(shù)據

2021-12-01 18:36:35

屬性

2011-05-20 16:18:23

ADO.NET

2021-03-10 10:55:51

SpringJava代碼

2024-06-27 08:26:10

LooperAndroid內存

2015-08-18 09:40:32

OpenStack Neutron虛擬網絡
點贊
收藏

51CTO技術棧公眾號