1. 程式人生 > >This Is Why We Coding

This Is Why We Coding

(1) BeanFactory

(2) BeanDefinition

1、 XmlBeanFactory(屌絲IOC)的整個流程

2、 FileSystemXmlApplicationContext 的IOC容器流程

1、高富帥IOC解剖

2、 設定資源載入器和資源定位

3、AbstractApplicationContext的refresh函式載入Bean定義過程:

4、AbstractApplicationContext子類的refreshBeanFactory()方法:

5、AbstractRefreshableApplicationContext子類的loadBeanDefinitions方法:

6、AbstractBeanDefinitionReader讀取Bean定義資源:

7、資源載入器獲取要讀入的資源:

8、XmlBeanDefinitionReader載入Bean定義資源:

9、DocumentLoader將Bean定義資源轉換為Document物件:

10、XmlBeanDefinitionReader解析載入的Bean定義資原始檔:

11、DefaultBeanDefinitionDocumentReader對Bean定義的Document物件解析:

12、BeanDefinitionParserDelegate解析Bean定義資原始檔中的<Bean>元素:

13、BeanDefinitionParserDelegate解析<property>元素:

14、解析<property>元素的子元素:

15、解析<list>子元素:

16、解析過後的BeanDefinition在IoC容器中的註冊:

17、DefaultListableBeanFactory向IoC容器註冊解析後的BeanDefinition:

總結:

1、依賴注入發生的時間

2、AbstractBeanFactory通過getBean向IoC容器獲取被管理的Bean:

3、AbstractAutowireCapableBeanFactory建立Bean例項物件:

4、createBeanInstance方法建立Bean的java例項物件:

5、SimpleInstantiationStrategy類使用預設的無參構造方法建立Bean例項化物件:

6、populateBean方法對Bean屬性的依賴注入:

7、BeanDefinitionValueResolver解析屬性值:

8、BeanWrapperImpl對Bean屬性的依賴注入:

一、什麼是Ioc/DI?

    IoC 容器:最主要是完成了完成物件的建立和依賴的管理注入等等。

先從我們自己設計這樣一個視角來考慮:

所謂控制反轉,就是把原先我們程式碼裡面需要實現的物件建立、依賴的程式碼,反轉給容器來幫忙實現。那麼必然的我們需要建立一個容器,同時需要一種描述來讓容器知道需要建立的物件與物件的關係。這個描述最具體表現就是我們可配置的檔案。

物件和物件關係怎麼表示?

可以用 xml , properties 檔案等語義化配置檔案表示。

描述物件關係的檔案存放在哪裡?

可能是 classpath , filesystem ,或者是 URL 網路資源, servletContext 等。

回到正題,有了配置檔案,還需要對配置檔案解析。

不同的配置檔案對物件的描述不一樣,如標準的,自定義宣告式的,如何統一? 在內部需要有一個統一的關於物件的定義,所有外部的描述都必須轉化成統一的描述定義。

如何對不同的配置檔案進行解析?需要對不同的配置檔案語法,採用不同的解析器。

IOC涉及到的類比較多,結構較為複雜,在分析之前需要先抓住九個關鍵的類系(之所以用類系來形容是因為下面所列出來的不是某個具體的實現類,而是從介面到抽象類等一些系列相關類/介面):

  BeanFactory:bean的管理工廠,所有的bean都在該物件中進行建立、儲存和銷燬。

  DefaultListableBeanFactory:beanFactory具體實現類

  Resource:spring的配置資訊,該資訊可能來源於xml檔案,可能來源於網路,也可能來源於資料流中。不管他從哪裡來的,都封裝為Resource物件。

  BeanDefinition:bean的所有資訊在該物件中進行封裝,包括bean的引數值、方法名、是否懶載入、是否為單例等各種資訊

  BeanDefinitionReader:見名知意,構建BeanDefinition的reader,也就是通過該Reader從Resource中讀取資訊封裝為BeanDefinition。

  ApplicationContext:俗稱“上下文”和“控制反轉”一樣晦澀難懂,據我猜測之所以這樣命名,是因為context繼承了太多的介面,具有各種各樣的功能,可以稱為萬能的上帝。並且所有的需要用到的bean都可以在其中取到,起到溝通上下的橋樑的作用,所以叫做“上下文”。這裡可以看出其特性是:實現了各種功能介面,封裝了各種bean物件。

  Environment:執行環境配置資訊,也就是一些配置屬性,來源於:properties檔案,JVM properties,system環境變數,JNDI, servlet context parameters上下文引數,專門的Properties物件,Maps等等

  Document:從xml檔案檔案中抽取出來的本文物件。

  Element:從Document中取出的node節點


二、 Spring IOC體系結構?

(1) BeanFactory

         Spring Bean的建立是典型的工廠模式,這一系列的Bean工廠,也即IOC容器為開發者管理物件間的依賴關係提供了很多便利和基礎服務,在Spring中有許多的IOC容器的實現供使用者選擇和使用,其相互關係如下:

其中BeanFactory作為最頂層的一個介面類,它定義了IOC容器的基本功能規範,BeanFactory 有三個子類:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是從上圖中我們可以發現最終的預設實現類是 DefaultListableBeanFactory,他實現了所有的介面。那為何要定義這麼多層次的介面呢?查閱這些介面的原始碼和說明發現,每個介面都有他使用的場合,它主要是為了區分在 Spring 內部在操作過程中物件的傳遞和轉化過程中,對物件的資料訪問所做的限制。例如 ListableBeanFactory 介面表示這些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關係的,也就是每個Bean 有可能有父 Bean。AutowireCapableBeanFactory 介面定義 Bean 的自動裝配規則。這四個介面共同定義了 Bean 的集合、Bean 之間的關係、以及 Bean 行為.

最基本的IOC容器介面BeanFactory

複製程式碼
1 public interface BeanFactory {    
2      
3      //對FactoryBean的轉義定義,因為如果使用bean的名字檢索FactoryBean得到的物件是工廠生成的物件,    
4      //如果需要得到工廠本身,需要轉義           
5      String FACTORY_BEAN_PREFIX = "&"; 
6         
7      //根據bean的名字,獲取在IOC容器中得到bean例項    
8      Object getBean(String name) throws BeansException;    
9    
10     //根據bean的名字和Class型別來得到bean例項,增加了型別安全驗證機制。    
11      Object getBean(String name, Class requiredType) throws BeansException;    
12     
13     //提供對bean的檢索,看看是否在IOC容器有這個名字的bean    
14      boolean containsBean(String name);    
15     
16     //根據bean名字得到bean例項,並同時判斷這個bean是不是單例    
17     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
18     
19     //得到bean例項的Class型別    
20     Class getType(String name) throws NoSuchBeanDefinitionException;    
21     
22     //得到bean的別名,如果根據別名檢索,那麼其原名也會被檢索出來    
23    String[] getAliases(String name);    
24     
 }
複製程式碼

在BeanFactory裡只對IOC容器的基本行為作了定義,根本不關心你的bean是如何定義怎樣載入的。正如我們只關心工廠裡得到什麼的產品物件,至於工廠是怎麼生產這些物件的,這個基本的介面不關心。

            而要知道工廠是如何產生物件的,我們需要看具體的IOC容器實現,spring提供了許多IOC容器的實現。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是針對最基本的ioc容器的實現,這個IOC容器可以讀取XML檔案定義的BeanDefinition(XML檔案中對bean的描述),如果說XmlBeanFactory是容器中的屌絲,ApplicationContext應該算容器中的高帥富.

            ApplicationContext是Spring提供的一個高階的IoC容器,它除了能夠提供IoC容器的基本功能外,還為使用者提供了以下的附加服務。

從ApplicationContext介面的實現,我們看出其特點:

         1.  支援資訊源,可以實現國際化。(實現MessageSource介面)

         2.  訪問資源。(實現ResourcePatternResolver介面,這個後面要講)

         3.  支援應用事件。(實現ApplicationEventPublisher介面)

(2) BeanDefinition

         SpringIOC容器管理了我們定義的各種Bean物件及其相互的關係,Bean物件在Spring實現中是以BeanDefinition來描述的,其繼承體系如下:

Bean 的解析過程非常複雜,功能被分的很細,因為這裡需要被擴充套件的地方很多,必須保證有足夠的靈活性,以應對可能的變化。Bean 的解析主要就是對 Spring 配置檔案的解析。這個解析過程主要通過下圖中的類完成:

三、IoC容器的初始化?

       IoC容器的初始化包括BeanDefinition的Resource定位、載入和註冊這三個基本的過程。我們以ApplicationContext為例講解,ApplicationContext系列容器也許是我們最熟悉的,因為web專案中使用的XmlWebApplicationContext就屬於這個繼承體系,還有ClasspathXmlApplicationContext等,其繼承體系如下圖所示:

ApplicationContext允許上下文巢狀,通過保持父上下文可以維持一個上下文體系。對於bean的查詢可以在這個上下文體系中發生,首先檢查當前上下文,其次是父上下文,逐級向上,這樣為不同的Spring應用提供了一個共享的bean定義環境。

下面我們分別簡單地演示一下兩種ioc容器的建立過程

1、XmlBeanFactory(屌絲IOC)的整個流程

通過XmlBeanFactory的原始碼,我們可以發現:

複製程式碼
 public class XmlBeanFactory extends DefaultListableBeanFactory{


     private final XmlBeanDefinitionReader reader; 
 

     public XmlBeanFactory(Resource resource)throws BeansException{
         this(resource, null);
     }
     

     public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)
          throws BeansException{
         super(parentBeanFactory);
         this.reader = new XmlBeanDefinitionReader(this);
         this.reader.loadBeanDefinitions(resource);
    }
 }
複製程式碼 複製程式碼
//根據Xml配置檔案建立Resource資源物件,該物件中包含了BeanDefinition的資訊
 ClassPathResource resource =new ClassPathResource("application-context.xml");
//建立DefaultListableBeanFactory
 DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
//建立XmlBeanDefinitionReader讀取器,用於載入BeanDefinition。之所以需要BeanFactory作為引數,是因為會將讀取的資訊回撥配置給factory
 XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader執行載入BeanDefinition的方法,最後會完成Bean的載入和註冊。完成後Bean就成功的放置到IOC容器當中,以後我們就可以從中取得Bean來使用
 reader.loadBeanDefinitions(resource);
複製程式碼

通過前面的原始碼,this.reader = new XmlBeanDefinitionReader(this); 中其中this 傳的是factory物件

2、FileSystemXmlApplicationContext 的IOC容器流程

1、高富帥IOC解剖

1   ApplicationContext =new FileSystemXmlApplicationContext(xmlPath);

先看其建構函式:

   呼叫建構函式:

複製程式碼
/**
* Create a new FileSystemXmlApplicationContext, loading the definitions
* from the given XML files and automatically refreshing the context.
* @param configLocations array of file paths
* @throws BeansException if context creation failed
 */public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }
複製程式碼

實際呼叫

複製程式碼
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
            throws BeansException {    
        super(parent);  
        setConfigLocations(configLocations);  
        if (refresh) {  
            refresh();  
        }  
    } 
複製程式碼

2、設定資源載入器和資源定位

通過分析FileSystemXmlApplicationContext的原始碼可以知道,在建立FileSystemXmlApplicationContext容器時,構造方法做以下兩項重要工作:

首先,呼叫父類容器的構造方法(super(parent)方法)為容器設定好Bean資源載入器。

然後,再呼叫父類AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法設定Bean定義資原始檔的定位路徑。

通過追蹤FileSystemXmlApplicationContext的繼承體系,發現其父類的父類AbstractApplicationContext中初始化IoC容器所做的主要原始碼如下:

複製程式碼
public abstract class AbstractApplicationContext extends DefaultResourceLoader  
        implements ConfigurableApplicationContext, DisposableBean {  
    //靜態初始化塊,在整個容器建立過程中只執行一次  
    static {  
        //為了避免應用程式在Weblogic8.1關閉時出現類載入異常載入問題,載入IoC容  
       //器關閉事件(ContextClosedEvent)類  
        ContextClosedEvent.class.getName();  
    }  
    //FileSystemXmlApplicationContext呼叫父類構造方法呼叫的就是該方法  
    public AbstractApplicationContext(ApplicationContext parent) {  
        this.parent = parent;  
        this.resourcePatternResolver = getResourcePatternResolver();  
    }  
    //獲取一個Spring Source的載入器用於讀入Spring Bean定義資原始檔  
    protected ResourcePatternResolver getResourcePatternResolver() {  
        // AbstractApplicationContext繼承DefaultResourceLoader,也是一個S  
        //Spring資源載入器,其getResource(String location)方法用於載入資源  
        return new PathMatchingResourcePatternResolver(this);  
    }   
……  
} 
複製程式碼

AbstractApplicationContext構造方法中呼叫PathMatchingResourcePatternResolver的構造方法建立Spring資源載入器:

public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {  
        Assert.notNull(resourceLoader, "ResourceLoader must not be null");  
        //設定Spring的資源載入器  
        this.resourceLoader = resourceLoader;  
} 

在設定容器的資源載入器之後,接下來FileSystemXmlApplicationContet執行setConfigLocations方法通過呼叫其父類AbstractRefreshableConfigApplicationContext的方法進行對Bean定義資原始檔的定位,該方法的原始碼如下:

複製程式碼
    //處理單個資原始檔路徑為一個字串的情況  
    public void setConfigLocation(String location) {  
       //String CONFIG_LOCATION_DELIMITERS = ",; /t/n";  
       //即多個資原始檔路徑之間用” ,; /t/n”分隔,解析成陣列形式  
        setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));  
    }  

    //解析Bean定義資原始檔的路徑,處理多個資原始檔字串陣列  
     
5.7 mysql命令gruop by報錯 this is incompatible with sql_mode=only_full_group_by

轉自:https://www.cnblogs.com/jim2016/p/6322703.html 在mysql 工具 搜尋或者插入資料時報下面錯誤: ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY

type Exception report message The Struts dispatcher cannot be found. This is usually caused by using

1.解決方法 將web.xml 的過濾器,從 .action 修改為: / <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-insta

mysql5.7.x:this is incompatible with DISTINCT

DISTINCT關鍵字經常在MySQL中使用,在mysql5.7以前的版本中一般沒有什麼問題,但是在5.7以後的版本中會遇到這樣的錯誤 Caused by: java.sql.SQLException: Expression #1 of ORDER BY clause is not in