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