1. 程式人生 > >關於Spring的那點事

關於Spring的那點事


一.Spring約束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//上面兩個是基礎IOC的約束,必備
xmlns:context="http://www.springframework.org/schema/context"
//上面一個是開啟註解管理Bean物件的約束
xmlns:aop="http://www.springframework.org/schema/aop"
// aop的註解約束
xmlns:tx="http://www.springframework.org/schema/tx"
// 事務的約束
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
// 上面兩個是基礎IOC的約束,必備
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
//上面一個是開啟註解管理Bean物件的約束
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
//aop的註解約束
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
//事務的約束
default-autowire="byName" default-lazy-init="false">

結論:不要在Spring的配置裡,配置上XSD的版本號,因為如果沒有配置版本號,取的就是當前jar裡的XSD檔案,減少了各種風險。而且這樣約定大於配置的方式很優雅。

14.spring的生命週期
如果從大體上區分值分只為四個階段
a.BeanFactoyPostProcessor例項化
b.Bean例項化,然後通過某些BeanFactoyPostProcessor來進行依賴注入
c.BeanPostProcessor的呼叫.Spring內建的BeanPostProcessor負責呼叫Bean實現的介面: BeanNameAware, BeanFactoryAware, ApplicationContextAware等等,
這些內建的BeanPostProcessor呼叫完後才會呼叫自己配置的BeanPostProcessor
d.Bean銷燬階段

 

二.IOC(控制反轉)

在類和類之間存在控制權,控制權指的是物件的建立和使用。就是由spring來負責控制物件的生命週期和物件間的關係。
比如:有類A和類B,之前的做法是在A中呼叫B,那麼控制權就在A中,這樣做的耦合度較高,如果修改了B,A也要做相應修改。
引入Spring框架後,控制權由Spring容器來負責。當A想使用B時,需要由Spirng容器通過 配置檔案迚行注入。
這種思想就是IoC(為了更好的理解,可以這樣認為,物件建立和使用 的控制權轉移到了Spring容器,由Spring容器來控制)。
用setter方法,然後在配置檔案中指定依賴關係。好比現實生活中的中介。比如:找工作需要中介服務商。
底層原理就是Java反射。反射(reflection),它允許程式在執行的時候動態的生成物件、執行物件的方法、改變物件的屬性,spring就是通過反射來實現注入的。
在Spring中,預設情況下是使用java動態代理技術來實現,當需要代理的類不是介面型別的時候,Spring會自動切換為CGLIB來進行代理。

容器是spring的核心,使IoC管理所有和元件
spring的兩種容器:a、BeanFactoy,b、ApplicationContext應用上下文
BeanFactory:BeanhFactory使用延遲載入所有的Bean,為了從BeanhFactory得到一個Bean,只要呼叫getBean()方法,就能獲得Bean

ApplicationContext:a、提供文字資訊解析,支援I18N
b、提供載入檔案資源的通用方法
c、向註冊為監聽器的Bean傳送事件
d、ApplicationContext介面擴充套件BeanFactory介面
e、ApplicationContext提供附加功能
5、ApplicationContext的三個實現類:a、ClassPathXmlApplication:把上下文檔案當成類路徑資源
b、FileSystemXmlApplication:從檔案系統中的XML檔案載入上下文定義資訊
c、XmlWebApplicationContext:從Web系統中的XML檔案載入上下文定義資訊

6、在預設情況下,Bean全都是單態,在<bean>中的singleton為false
7、<bean>中的id屬性必須遵循Java規範,而name屬性可以不遵循
8、Bean的例項化的時候需要一些初始化的動作,同樣當不再使用的時候,需要從容器中將其銷燬
9、物件的初始化:<bean init-method="方法名">
10、物件的銷燬:<bean destroy-method="方法名">
銷燬物件的過程:a、主執行緒先被中斷
b、Java虛擬機器使用垃圾回收機制回收Bean物件
11、Bean設定:設值注入:1)簡單配置:<bean id="xxx" class="Bean的全稱類名">
        <property name="xx" value="xxxxx"></property>
      </bean>
value中的值可以是基本資料型別或者String型別,spring將會自動判斷設定的型別並且將其轉換成合適的值
2)引用配置:<bean id="xxx" class="Bean的全稱類名">
     <property name="xx" ref="xxxxx"></property>
   </bean>
ref中的值是引用資料型別,spring容器會完成獲取工作
3)List和陣列:<bean id="xxx" class="Bean的全稱類名">
<property name="list">
<list>
<value></value>
<ref bean=""/>
</list>
</property>
</bean>
list元素內可以是任何元素,但不能違背Bean所需要的物件型別
4)Set配置:和<list>一樣,將<list>改成<set>
5)Map配置:Map中的每條資料是由一個鍵和一個值組成,用<entry>元素來定義
<bean id="xxx" class="Bean的全稱類名">
<property name="list">
<entry key="key1">
<value></value>
</entry>
</property>
</bean>
<bean id="xxx" class="Bean的全稱類名">
<property name="list">
<entry key="key1">
<ref bean=""/>
</entry>
</property>
</bean>
注意:配置entry時,屬性key的值只能是String,因為Map通常用String作為主鍵
6)Properties配置:使用<props>和<map>相似,最大區別是<prop>的值都是String
注意:使用設值注入必須要有set方法,通過name屬性找set方法
優勢:a、通過set()方法設定更直觀,更自然
b、當依賴關係較複雜時,使用set()方法更清晰
構造子注入:必須要有無參和帶參的構造方法,加上index(值從0開始)屬性避免注入混淆
<constractor-arg>
注意:設值注入可以和構造子注入混合使用。先呼叫構造方法產生物件,再呼叫set()方法賦值。但只使用設值注入時,會先呼叫無參的構造方法
優勢:a、依賴關係一次性設定,對外不準修改
b、無需關心方式
c、注入有先後順序,防止注入失敗

Spring的IoC容器就是一個實現了BeanFactory介面的可例項化類。事實上,Spring提供了兩種不同的容器:一種是最基本的BeanFactory,
另一種是擴充套件的ApplicationContext。BeanFactory 僅提供了最基本的依賴注入支援,而 ApplicationContext 則擴充套件了BeanFactory ,
提供了更多的額外功能。二者對Bean的初始化也有很大區別。BeanFactory當需要呼叫時讀取配置資訊,生成某個類的例項。如果讀入的Bean配置正確,則其他的配置中有錯誤也不會影響程式的執行。
而ApplicationContext 在初始化時就把 xml 的配置資訊讀入記憶體,對 XML 檔案進行檢驗,如果配置檔案沒有錯誤,就建立所有的Bean ,直接為應用程式服務。
相對於基本的BeanFactory,ApplicationContext 唯一的不足是佔用記憶體空間。當應用程式配置Bean較多時,程式啟動較慢。

ApplicationContext會利用Java反射機制自動識別出配置檔案中定義的BeanPostProcessor、InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,
並自動將它們註冊到應用上下文中;而BeanFactory需要在程式碼中通過手工呼叫addBeanPostProcessor()方法進行註冊。

Bean裝配實際上就是讓容器知道程式中都有哪些Bean,可以通過以下兩種方式實現:
配置檔案(最為常用,體現了依賴注入DI的思想)
程式設計方式(寫的過程中向BeanFactory去註冊)


作用:

1. BeanFactory負責讀取bean配置文件,管理bean的載入,例項化,維護bean之間的依賴關係,負責bean的宣告週期。
2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,還提供了更完整的框架功能:
a. 國際化支援
b. 資源訪問:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件傳遞:通過實現ApplicationContextAware介面
3. 常用的獲取ApplicationContext的方法:
FileSystemXmlApplicationContext:從檔案系統或者url指定的xml配置檔案建立,引數為配置檔名或檔名陣列
ClassPathXmlApplicationContext:從classpath的xml配置檔案建立,可以從jar包中讀取配置檔案
WebApplicationContextUtils:從web應用的根目錄讀取配置檔案,需要先在web.xml中配置,可以配置監聽器或者servlet來實現
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
這兩種方式都預設配置檔案為web-inf/applicationContext.xml,也可使用context-param指定配置檔案
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>

 

三.AOP(面向切面)

為什麼要用AOP?
面向物件的特點是繼承、多型和封裝。而封裝就要求將功能分散到不同的物件中去,這在軟體設計中往往稱為職責分配。實際上也就是說,讓不同的類設計不同的方法。
這樣程式碼就分散到一個個的類中去了。這樣做的好處是降低了程式碼的複雜程度,使類可重用。
但是在分散程式碼的同時,也增加了程式碼的重複性。什麼意思呢?比如說,在兩個類中,可能都需要在每個方法中做日誌。按面向物件的設計方法,就必須在兩個類的方法中都加入日誌的內容。
也許他們是完全相同的,但就是因為面向物件的設計讓類與類之間無法聯絡,而不能將這些重複的程式碼統一起來。
也許有人會說,那好辦啊,可以將這段程式碼寫在一個獨立的類獨立的方法裡,然後再在這兩個類中呼叫。但是,這樣一來,這兩個類跟我們上面提到的獨立的類就有耦合了,它的改變會影響這兩個類。
那麼,有沒有什麼辦法,能讓我們在需要的時候,隨意地加入程式碼呢?

什麼是AOP?
這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式設計。
一般而言,管切入到指定類指定方法的程式碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點。
有了AOP,就可以把幾個類共有的程式碼,抽取到一個切片中,等到需要時再切入物件中去,從而改變其原有的行為。
實現AOP的技術,主要分為兩大類:一是採用動態代理技術,利用擷取訊息的方式,對該訊息進行裝飾,以取代原有物件行為的執行;
二是採用靜態織入的方式,引入特定的語法建立“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的程式碼。
jdk動態代理的缺陷是:它只能代理介面,而不能沒有代理沒有介面的類。

Spring的bean就相當於定義一個元件,這個元件是用於具體實現某個功能的。
這裡的所定義的bean就相當於給了一個簡潔方便的方法來呼叫這個元件實現要完成的功能。
對於Spring最主要的應該就是由這些bean組成的bean工廠,每個bean實現一個功能。

其他的屬性:
Id:標識該bean的名稱,通過factory.getBean(“id”)來獲得例項。
Class:該bean的類路徑。
Singleton:預設為true,即單例項模式,每次getBean(“id”)時獲取的都是同一個例項,如果設定為false,即原型模式,則每次獲取的是新建立的例項。
Init-method:在bean例項化後要呼叫的方法(bean裡定義好的方法)。
Destroy-method:bean從容器裡刪除之前要呼叫的方法。
Autowire:其屬性要通過何種方法進行屬性的自動裝配。
對於上述的各個屬性,id和class是必要的,其他的則可以省略。例如如果設定了autowire的值,則表明需要自動裝配,否則是手動裝配。

一般而言,使用Spring框架的主要作用: 會使用IOC整合元件(各種Bean),使用AOP來管理事務。

AOP有2種:基於xml配置檔案方式:1.定義切面;2.宣告切入點;3.應用通知。
註解方式:1.在配置檔案中啟用對切面的註解;2.在切面類中用註解來定義切面,宣告切入和應用切面。

使用場景

事務管理:
a.使用宣告書事務管理:
b.使用程式設計式事務管理:程式設計式即採用註解的方式,需要注意的是,使用註解的方式需要在Spring的配置檔案中加入一句話:<context:annotation-config/>,其作用是開啟註解的方式。

類頭的@Transactional為預設事務配置,如方法沒有自己的事務型別,則按預設事務,如有自己的配置,則按自己的配置。

spring只是控制資料庫的事務提交和回滾,藉助於java的反射機制,在事務控制的方法(通常是service層的方法)前後獲取事務開啟session,
然後執行資料操作,如果方法內有異常被丟擲,spring會捕獲異常並回滾在這個方法內所有的資料操作,如果成功則提交所有的資料,最後spring會幫關閉需要關閉的東西。
所以spring想要做的是,要程式設計師專注於寫邏輯,不需要關係資料庫何時開啟和關閉連線。

Spring配置檔案中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,
無論哪種配置方式,一般變化的只是代理機制這部分。 DataSource、 TransactionManager這兩部分只是會根據資料訪問方式有所變化,
比如使用Hibernate進行資料訪問時,DataSource實際為 SessionFactory,TransactionManager的實現為HibernateTransactionManager。