Spring

目錄
? ? 1 數(shù)據(jù)交換格式
? ? 2 Java反射
? ? 3 Spring簡(jiǎn)介
? ? 4 Spring IOC
? ? 5 代理
? ? 6 Spring AOP
? ? 7 Spring MVC
? ? 8 Spring JDBC
? ? 9 Spring 事務(wù)
? ? 10 Spring 遠(yuǎn)端調(diào)用
? ??11 Spring代碼

參考資料:
· 《Spring 技術(shù)內(nèi)幕》
·? JavaG
·? JavaD
·? 簡(jiǎn)書文章

1 數(shù)據(jù)交換格式

????客戶端與服務(wù)器常用數(shù)據(jù)交換格式xml、JSON、html。XML是重量級(jí)數(shù)據(jù)格式,傳輸過程中占帶寬較大,傳輸效率不高;JSON是輕量級(jí)的數(shù)據(jù)格式,占帶寬較小。

1.1 應(yīng)用場(chǎng)景

· 移動(dòng)端、互聯(lián)網(wǎng)項(xiàng)目,大多采用http+JSON,走restful風(fēng)格。
· webService服務(wù)采用http+XML,多用于銀行項(xiàng)目。

1.2 JSON

????JSON(JavaScript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式,相比于xml這種數(shù)據(jù)交換格式來說,因?yàn)榻馕鰔ml比較的復(fù)雜,而且需要編寫大段的代碼,所以客戶端和服務(wù)器的數(shù)據(jù)交換格式往往通過JSON來進(jìn)行交換。
樣例:

{
????"sites": [
????????????????{
????????????????????"name": "baidu",
????????????????????"url": "www.baidu.com"
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
????????????????????"name": "sougou",
????????????????????"url": "www.sougou.com"
????????????????}
????????????????]
}

1.2.1 JSON格式說明

????JSON的形式是用大括號(hào)“{}”包圍起來的項(xiàng)目列表,每一個(gè)項(xiàng)目間用逗號(hào)(,)分隔,而項(xiàng)目就是用冒號(hào)(:)分隔的屬性名和屬性值。這是典型的字典表示形式,也再次表明javascript里的對(duì)象就是字典結(jié)構(gòu)。不管多么復(fù)雜的對(duì)象,都可以用一句JSON代碼來創(chuàng)建并賦值。在JSON中,名稱/值對(duì)包括字段名稱(在雙引號(hào)中),后面寫一個(gè)冒號(hào),然后是值。

????json簡(jiǎn)單說就是javascript中的對(duì)象和數(shù)組,所以這兩種結(jié)構(gòu)就是對(duì)象數(shù)組兩種結(jié)構(gòu),通過這兩種結(jié)構(gòu)可以表示各種復(fù)雜的結(jié)構(gòu)

(1)對(duì)象:對(duì)象在js中表示為“{}”括起來的內(nèi)容,數(shù)據(jù)結(jié)構(gòu)為?{key:value,key:value,...}的鍵值對(duì)的結(jié)構(gòu),在面向?qū)ο蟮恼Z言中,key為對(duì)象的屬性,value為對(duì)應(yīng)的屬性值,所以很容易理解,取值方法為 對(duì)象.key?獲取屬性值,這個(gè)屬性值的類型可以是 數(shù)字、字符串、數(shù)組、對(duì)象幾種。

(2)數(shù)組:數(shù)組在js中是中括號(hào)“[]”括起來的內(nèi)容,數(shù)據(jù)結(jié)構(gòu)為?["java","javascript","vb",...],取值方式和所有語言中一樣,使用索引獲取,字段值的類型可以是 數(shù)字、字符串、數(shù)組、對(duì)象幾種。經(jīng)過對(duì)象、數(shù)組2種結(jié)構(gòu)就可以組合成復(fù)雜的數(shù)據(jù)結(jié)構(gòu)了。

1.2.2 fastjson

????常用的JSON解析框架有:fastjson(阿里)、gson(谷歌)、jackson(SpringMVC自帶)。下面主要介紹阿里的fastjson

1.2.2.1 maven依賴

<dependency>

????<groupId>com.alibaba</groupId>

????<artifactId>fastjson</artifactId>

????<version>1.1.43</version>

</dependency>

1.2.2.2 解析json

static?String jsonStr?= "{\"sites\":[{\"name\":\"baidu\",\"url\":\"www.baidu.com\"},{\"name\":\"sougou\",\"url\":\"www.sougou.com/\"}]}";? public?static?void?main(String[] args) {
????JSONObject jsonObject?= new?JSONObject(); // 將json字符串轉(zhuǎn)為jsonbject
????JSONObject jsonStrObject?= jsonObject.parseObject(jsonStr); // 這里也可以用JSON.parseObject(jsonStr)
????JSONArray jsonArray?= jsonStrObject.getJSONArray("sites");
????for?(Object object?: jsonArray) {
????????JSONObject stObject?= (JSONObject) object;
????????String name?= stObject.getString("name");
????????String url?= stObject.getString("url");
????????System.out.println(name?+ "---"?+ url);
????}
}

1.2.2.3 組裝json

JSONObject jsonObject?= new?JSONObject();
JSONArray jsonArray?= new?JSONArray();
JSONObject stObject?= new?JSONObject();
stObject.put("name", "baidu");
stObject.put("url", "http://www.baidu.com");
jsonArray.add(stObject);
jsonObject.put("sites", jsonArray);
System.out.println(jsonObject.toJSONString());//這里也可以用JSON.toJSONString(root, SerializerFeature.WriteMapNullValue);后面的參數(shù)為是否顯示null值等控制參數(shù)。

1.3 XML

????它是可擴(kuò)展標(biāo)記語言(Extensible Markup Language,簡(jiǎn)稱XML),是一種標(biāo)記語言。主要用于描述數(shù)據(jù)和用作配置文件。

????XML文檔在邏輯上主要由一下 5 個(gè)部分組成:

????(1)XML聲明:指明所用 XML 的版本、文檔的編碼、文檔的獨(dú)立性信息

????(2)文檔類型聲明:指出XML文檔所用的 DTD

????(3)元素:由開始標(biāo)簽、元素內(nèi)容和結(jié)束標(biāo)簽構(gòu)成

????(4)注釋:以結(jié)束,用于對(duì)文檔中的內(nèi)容起一個(gè)說明作用

????(5)處理指令:通過處理指令來通知其他應(yīng)用程序來處理非XML格式的數(shù)據(jù),格式為

  XML文檔的根元素被稱為文檔元素,它和在其外部出現(xiàn)的處理指令、注釋等作為文檔實(shí)體的子節(jié)點(diǎn),根元素本身和其內(nèi)部的子元素也是一棵樹。

<?xml version="1.0" encoding="UTF-8"?>
????<students>
????????<student1 id="001">
????????????<微信公眾號(hào)>@殘缺的孤獨(dú)</微信公眾號(hào)>
????????????<學(xué)號(hào)>20140101</學(xué)號(hào)>
????????????<地址>北京海淀區(qū)</地址>
????????????<座右銘>要么強(qiáng)大,要么聽話</座右銘>
? ? ? ? </student1>
????????<student2 id="002">
????????????<新浪微博>@殘缺的孤獨(dú)</新浪微博>
????????????<學(xué)號(hào)>20140102</學(xué)號(hào)>
????????????<地址>北京朝陽區(qū)</地址>
????????????<座右銘>在哭泣中學(xué)會(huì)堅(jiān)強(qiáng)</座右銘>
????????</student2>
????</students> ?

1.3.1 常用解析XML方法

? ?常用解析框架: Dom4j、Sax、Pull。

· Dom4j與Sax區(qū)別
????dom4j不適合大文件的解析,因?yàn)樗且幌伦訉⑽募虞d到內(nèi)存中,所以有可能出現(xiàn)內(nèi)存溢出,sax是基于事件來對(duì)xml進(jìn)行解析的,所以他可以解析大文件的xml,也正是因?yàn)槿绱?,所以dom4j可以對(duì)xml進(jìn)行靈活的增刪改查和導(dǎo)航,而sax沒有這么強(qiáng)的靈活性,所以sax經(jīng)常是用來解析大型xml文件,而要對(duì)xml文件進(jìn)行一些靈活(crud)操作就用dom4j。

1.3.2 dom4j

1.3.2.1 dom4j獲取Document對(duì)象方法

????解析XML過程是通過獲取Document對(duì)象,然后繼續(xù)獲取各個(gè)節(jié)點(diǎn)以及屬性等操作,因此獲取Document對(duì)象是第一步,大體說來,有三種方式

(1)自己創(chuàng)建Document對(duì)象

Document?document?= DocumentHelper.createDocument();

Element root?= document.addElement("students");

其中students是根節(jié)點(diǎn),可以繼續(xù)添加其他節(jié)點(diǎn)等操作。

(2)自己創(chuàng)建Document對(duì)象

//創(chuàng)建SAXReader對(duì)象

SAXReader?reader?= new?SAXReader();

//讀取文件 轉(zhuǎn)換成Document

Document?document?= reader.read(new?File("XXXX.xml"));

(3)讀取XML文本內(nèi)容獲取Document對(duì)象

String xmlStr?= "<students>......</students>";

Document?document?= DocumentHelper.parseText(xmlStr);

1.3.2.2 dom4j解析Demo

public?static?void?main(String[] args) throws?DocumentException {
????SAXReader saxReader?= new?SAXReader();
????Document read?= saxReader.read(new?File("E://work//spring-ioc//src//main//resources//stu.xml"));
????// 獲取根節(jié)點(diǎn)
????Element rootElement?= read.getRootElement();
????getNodes(rootElement);
}
static?public?void?getNodes(Element rootElement) {
????System.out.println("當(dāng)前節(jié)點(diǎn)名稱:"?+ rootElement.getName());
????// 獲取屬性ID
????List<Attribute> attributes?= rootElement.attributes();
????for?(Attribute attribute?: attributes) {
????????System.out.println("屬性:"?+ attribute.getName() + "---"?+ attribute.getText());
????}
????if?(!rootElement.getTextTrim().equals("")){
????????System.out.println(rootElement.getName() + "--"?+ rootElement.getText()); }
????????// 使用迭代器遍歷
????????Iterator<Element> elementIterator?= rootElement.elementIterator();
????????while?(elementIterator.hasNext()) {
????????????Element next?= elementIterator.next();
????????????getNodes(next);
????????}
}

2 Java反射

2.1 反射的作用

(1)動(dòng)態(tài)創(chuàng)建對(duì)象,不適用new。
(2)反編譯:.class -> .java
(3)訪問java對(duì)象的屬性、方法、構(gòu)造方法等。

2.2 應(yīng)用場(chǎng)景

(1)JDBC加載驅(qū)動(dòng)
(2)Spring IOC,原理即反射+dom4j。
(3)框架的配置文件中,含有class=“....”等字樣。

2.3 獲取class對(duì)象的方法

(1) Class c1 = Class.forName(“類的全限定名”);
(2) Class c2 = 類名.class;
(3) Class c3 = this.getClass();

2.4 通過反射創(chuàng)建對(duì)象

Class<?> forName?= Class.forName("com.qian.entity.User");
????// 創(chuàng)建此Class 對(duì)象所表示的類的一個(gè)新實(shí)例 調(diào)用了User的無參數(shù)構(gòu)造方法.
Object newInstance?= forName.newInstance();

2.5 相關(guān)API

圖2-1 反射API

3 Spring簡(jiǎn)介

????spring是一個(gè)開源框架,它由Rod Johnson創(chuàng)建。它是為了解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性而創(chuàng)建的。Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限于服務(wù)器端的開發(fā)。從簡(jiǎn)單性、可測(cè)試性和松耦合的角度而言,任何Java應(yīng)用都可以從Spring中受益。
????Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架。
????輕量,從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個(gè)大小只有1MB多的JAR文件里發(fā)布。并且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應(yīng)用中的對(duì)象不依賴于Spring的特定類。
????控制反轉(zhuǎn),Spring通過一種稱作控制反轉(zhuǎn)(IoC)的技術(shù)促進(jìn)了松耦合。當(dāng)應(yīng)用了IoC,一個(gè)對(duì)象依賴的其它對(duì)象會(huì)通過被動(dòng)的方式傳遞進(jìn)來,而不是這個(gè)對(duì)象自己創(chuàng)建或者查找依賴對(duì)象。你可以認(rèn)為IoC與JNDI相反——不是對(duì)象從容器中查找依賴,而是容器在對(duì)象初始化時(shí)不等對(duì)象請(qǐng)求就主動(dòng)將依賴傳遞給它。
????面向切面,Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。
????容器,Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器,你可以配置你的每個(gè)bean如何被創(chuàng)建——基于一個(gè)可配置原型(prototype),你的bean可以創(chuàng)建一個(gè)單獨(dú)的實(shí)例或者每次需要時(shí)都生成一個(gè)新的實(shí)例——以及它們是如何相互關(guān)聯(lián)的。然而,Spring不應(yīng)該被混同于傳統(tǒng)的重量級(jí)的EJB容器,它們經(jīng)常是龐大與笨重的,難以使用。
????框架,Spring可以將簡(jiǎn)單的組件配置、組合成為復(fù)雜的應(yīng)用。在Spring中,應(yīng)用對(duì)象被聲明式地組合,典型地是在一個(gè)XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等等),將應(yīng)用邏輯的開發(fā)留給了你。
????所有Spring的這些特征使你能夠編寫更干凈、更可管理、并且更易于測(cè)試的代碼。它們也為Spring中的各種模塊提供了基礎(chǔ)支持。
????一般說的spring框架大都是Spring Framework,它是很多模塊的集合,使用這些模塊可以很方便地協(xié)助我們進(jìn)行開發(fā)。這些模塊包括核心容器、數(shù)據(jù)訪問/集成、Web、AOP面向切面編程、工具、消息和測(cè)試模塊。

圖 3-1 Spring簡(jiǎn)介

? ?· 列舉一些重要的spring模塊:
(1)Spring Core 包含IOC容器等。
(2)Spring Aspects 與AspectJ集成。
(3)Spring AOP 面向切面的編程實(shí)現(xiàn)。
(4)Spring JDBC 與Java數(shù)據(jù)庫對(duì)接。
(5)Spring JMS Java消息服務(wù)。
(6)Spring ORM 支持Hibernate等ORM工具
(7)Spring Web 創(chuàng)建web應(yīng)用程序提供支持
(8)Spring Test 提供對(duì)Junit和TestNG測(cè)試的支持。

4 Spring IOC

4.1 作用

? ? 創(chuàng)建對(duì)象和處理對(duì)象的依賴關(guān)系。
? ? 原理是:Java反射+dom4j

4.2 特點(diǎn)

? ? 控制反轉(zhuǎn)、依賴注入。
? ? 對(duì)象之間的依賴關(guān)系可以通過把對(duì)象的依賴注入交給框架或者IOC容器來完成,降低代碼的耦合度。在Spring的實(shí)現(xiàn)中,IOC容器是實(shí)現(xiàn)這個(gè)模式的載體,它可以在對(duì)象生成或初始化時(shí)直接將數(shù)據(jù)注入到對(duì)象中,也可以通過將對(duì)象引用注入到數(shù)據(jù)域中的方式來注入對(duì)方法調(diào)用的依賴。

4.3 IOC容器實(shí)現(xiàn)

? ? 在Spring IOC容器的設(shè)計(jì)中,有兩個(gè)主要的容器系列。一個(gè)是實(shí)現(xiàn)BeanFactory接口的簡(jiǎn)單容器系列,這個(gè)系列只實(shí)現(xiàn)了容器的最基本功能;另一個(gè)是ApplicationContext應(yīng)用上下文,它作為容器的高級(jí)形態(tài)而存在。

4.3.1 BeanFactory

圖4-1 BeanFactory接口關(guān)系圖

4.3.1.1 BeanFactory和FactoryBean區(qū)別

· BeanFactory定義了 IOC 容器的最基本形式,并提供了 IOC 容器應(yīng)遵守的的最基本的接口,也就是 Spring IOC 所遵守的最底層和最基本的編程規(guī)范。BeanFactory僅是個(gè)接口,并不是IOC容器的具體實(shí)現(xiàn)。所有的 Bean 都是由 BeanFactory( 也就是 IOC 容器 ) 來進(jìn)行管理。

public interface BeanFactory {
?????//FactoryBean前綴
?????String FACTORY_BEAN_PREFIX = "&";
?????//根據(jù)名稱獲取Bean對(duì)象
?????Object getBean(String name) throws BeansException;
?????///根據(jù)名稱、類型獲取Bean對(duì)象 <T>
? ? ?T getBean(String name, Class<T> requiredType) throws BeansException;
?????//根據(jù)類型獲取Bean對(duì)象 <T>
? ? ?T getBean(Class<T> requiredType) throws BeansException;
????//根據(jù)名稱獲取Bean對(duì)象,帶參數(shù)
?????Object getBean(String name, Object... args) throws BeansException;
?????//根據(jù)類型獲取Bean對(duì)象,帶參數(shù) <T>
? ? ?T getBean(Class<T> requiredType, Object... args) throws BeansException;
? ? ?//是否存在 boolean
? ? ?containsBean(String name);
?????//是否為單例
?????boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
?????//是否為原型(多實(shí)例)
? ? ?boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
?????//名稱、類型是否匹配
?????boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
?????//獲取類型
? ? ?Class<?> getType(String name) throws NoSuchBeanDefinitionException;
?????//根據(jù)實(shí)例的名字獲取實(shí)例的別名
?????String[] getAliases(String name);
}

·?FactoryBean工廠類接口,用戶可以通過實(shí)現(xiàn)該接口定制實(shí)例化 Bean 的邏輯。是一個(gè)能產(chǎn)生或者修飾對(duì)象生成的工廠Bean,可以在IOC容器中被管理,類似工廠模式和修飾器模式。當(dāng)使用容器中factory bean的時(shí)候,該容器不會(huì)返回factory bean本身,而是返回其生成的對(duì)象。

public interface FactoryBean<T> {
?????//FactoryBean 創(chuàng)建的 Bean 實(shí)例
?????T getObject() throws Exception;
?????//返回 FactoryBean 創(chuàng)建的 Bean 類型
?????Class<?> getObjectType();
?????//返回由 FactoryBean 創(chuàng)建的 Bean 實(shí)例的作用域是 singleton 還是 prototype
?????boolean isSingleton();
}

4.3.1.2 IOC容器的使用步驟:

(1)創(chuàng)建IOC配置文件的抽象資源,這個(gè)抽象資源包含了BeanDefinition的定義信息。
? ? ? ? ClassPathResource res = new ClassPathResource("bean.xml");
(2)創(chuàng)建一個(gè)BeanFactory。
? ? ? ? DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
(3)創(chuàng)建一個(gè)BeanDefinitionReader。
? ? ? ? XmlBeanDefinitionReader reader = new?XmlBeanDefinitionReader(factory);
(4)加載配置信息,完成載入和注冊(cè)Bean定義。
? ? ? ? reader.loadBeanDefinitions(res);

· BeanDefinition
????BeanFactory 是 Bean 容器,那么 Bean 又是什么呢?這里的 BeanDefinition 就是我們所說的 Spring 的 Bean,我們自己定義的各個(gè) Bean 其實(shí)會(huì)轉(zhuǎn)換成一個(gè)個(gè) BeanDefinition 存在于 Spring 的 BeanFactory 中。所以 Bean 在代碼層面上可以簡(jiǎn)單認(rèn)為是 BeanDefinition 的實(shí)例BeanDefinition 中保存了我們的 Bean 信息,比如這個(gè) Bean 指向的是哪個(gè)類、是否是單例的、是否懶加載、這個(gè) Bean 依賴了哪些 Bean 等等。

4.3.2 ApplicationContext

圖 4-2?ApplicationContext接口關(guān)系圖

? ? 是一個(gè)高級(jí)形態(tài)意義的IOC容器。

????在BeanFactory的基礎(chǔ)上添加的新特性:
(1)擴(kuò)展MessageSource接口,支持不同的信息源。
(2)對(duì)ResourceLoader和Resource的支持,可以靈活得到Bean。
(3)繼承接口ApplicationEventPublisher,支持應(yīng)用事件
(4)豐富的附件功能,面向框架的風(fēng)格。

? ? 一個(gè)具體的應(yīng)用上下文,只需要實(shí)現(xiàn)和它自身設(shè)計(jì)相關(guān)的功能,如FileSystemXmlApplicationContext,需要實(shí)現(xiàn):
(1)對(duì)實(shí)例化應(yīng)用上下文的支持,啟動(dòng)IOC的refresh()過程。
(2)定義如何從文件加載Bean定義資源。

4.4 IOC源碼分析

圖4-3 IOC源碼分析 a
圖4-4 IOC源碼分析 b
圖4-5 IOC源碼分析 c
圖4-6 IOC初始化過程

· 一些注意點(diǎn)
(1)Bean的依賴注入發(fā)生在第一次getBean()方法調(diào)用時(shí)
(2)設(shè)置了lazyinit屬性的Bean,在IOC容器初始化完成注入
(3)創(chuàng)建bean實(shí)例的兩種方法:
? ? ? ? ? ? · BeanUtils中的JVM反射
? ? ? ? ? ? · CGLIB
(4)在Bean的創(chuàng)建和對(duì)象依賴注入中,遞歸完成依賴注入。

4.5 IOC中的Bean

4.5.1 Bean的作用域

(1)singleton 單例模式(默認(rèn))。Bean類中的全局變量用TheadLocal來定義,解決線程安全問題。
(2)prototype,每次請(qǐng)求會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。
(3)request,Http請(qǐng)求創(chuàng)建一個(gè)Bean,僅在當(dāng)前request有效。
(4)session,Http請(qǐng)求創(chuàng)建一個(gè)Bean,僅在當(dāng)前session有效。
(5)global-session,全局session,在基于portlet的web中有效。

4.5.2 Bean的生命周期

(1)Bean容器中找到Bean定義。
(2)創(chuàng)建bean實(shí)例
(3)bean屬性注入
(4)如果實(shí)現(xiàn)了*.Aware接口,調(diào)用setXXX()方法。
(5)如果實(shí)現(xiàn)了BeanPostProcess方法,調(diào)用postProcessBeforeInitialization方法。
(6)如果實(shí)現(xiàn)了InitializingBean接口,調(diào)用afterPropertiesSet方法。
(7)如果配置文件中定義包含Init-method屬性,執(zhí)行指定方法
(8)如果實(shí)現(xiàn)了BeanPostProcess方法,調(diào)用postProcessAfterInitialization()方法。
(9)如果實(shí)現(xiàn)了DisposableBean接口,執(zhí)行destroy()方法
(10)如果在配置文件中定義包含destroy-method屬性,執(zhí)行指定方法。

4.6 IOC中創(chuàng)建對(duì)象

????創(chuàng)建對(duì)象,有幾種方式:

1) 調(diào)用無參數(shù)構(gòu)造器

2) 帶參數(shù)構(gòu)造器

3) 工廠創(chuàng)建對(duì)象

????????工廠類,靜態(tài)方法創(chuàng)建對(duì)象

????????工廠類,非靜態(tài)方法創(chuàng)建對(duì)象

<!-- 無參構(gòu)造函數(shù) -->
<bean?id="user1"?class="com.qian.entity.UserEntity"?scope="prototype"?/>
<!-- 有參構(gòu)造函數(shù) -->
<bean?id="user2"?class="com.qian.entity.UserEntity">
?????<constructor-arg?name="name"?type="java.lang.String" value="張三"></constructor-arg>
? ? ?<constructor-arg?name="age"?type="java.lang.Integer" value="18"></constructor-arg>
</bean>?
<bean?id="factory"?class="com.qian.entity.ObjectFactory"></bean>
<!-- 通過實(shí)例工廠方法創(chuàng)建 -->
<bean?id="user3"?factory-bean="factory"?factory-method="getInstance"></bean>
<!-- 通過靜態(tài)工廠方法創(chuàng)建 -->
<bean?id="user4"?class="com.qian.entity.ObjectFactory" factory-method="getStaticInstance"></bean>

4.7 IOC的依賴注入(DI)

1)通過構(gòu)造函數(shù)

2)通過set方法給屬性注入值

3) p名稱空間

4) 注解
? ??使用注解步驟
? ? ? ? ·先引入context名稱空間
????????????xmlns:context="http://www.springframework.org/schema/context"
? ? ? ? ·開啟注解掃描
????????????<context:component-scan base-package="cn.itcast.e_anno2"></context:component-scan>
? ? ? ? ·使用注解,通過注解的方式,把對(duì)象加入ioc容器。
????????????創(chuàng)建對(duì)象以及處理對(duì)象依賴關(guān)系,相關(guān)的注解:

????????????@Component指定把一個(gè)對(duì)象加入IOC容器

????????????@Repository作用同@Component;在持久層使用(dao)

????????????@Service作用同@Component;在業(yè)務(wù)邏輯層使用

????????????@Controller作用同@Component;在控制層使用

????????????@Resource屬性注入

· 注意事項(xiàng)
? ? ·@autowired? spring框架自帶 ?默認(rèn)以類型查找

? ? ·@Resource是jdk1.6 ?默認(rèn)以名稱查找? 再以類型

? ? ·如果xml和注解混合使用,先走xml

? ? ·@Component 和 @Bean 的區(qū)別是什么?
? ? ? ? ? ? a. 作用對(duì)象不同:@Component注解作用于類,而@Bean注解作用于方法。
? ? ? ? ? ? b. @Component通常通過類路徑掃描(@ComponentScan)來自動(dòng)偵測(cè)以及自動(dòng)裝配到
????????????????Spring容器中;@Bean注解通常是在標(biāo)有該注解的方法中定義產(chǎn)生這個(gè)Bean,
????????????????@bean告訴Spring這是某個(gè)類的實(shí)例,當(dāng)需要它的時(shí)候還給我。
? ? ? ? ? ? c. @Bean注解比Component注解的自定義性更強(qiáng),而且很多地方只能通過@Bean注解
????????????????來注冊(cè)bean。特別是引用第三方庫中的類需要裝配到Spring容器時(shí),只能通過
????????????????@Bean實(shí)現(xiàn)。

@Bean
public OneService getService(status) {
?????case (status) {
?????????when 1: return new serviceImpl1();
?????????when 2: return new serviceImpl2();
?????????when 3: return new serviceImpl3();

????????}
}

5 代理

????代理指的是一個(gè)代理人(或替代品),它被授權(quán)代表另外一個(gè)人(或文檔)。

? ? 代理的一些特性:1.代理存在的意義就是代表另一個(gè)事物。2.代理至少需要完成(或?qū)崿F(xiàn))它所代表的事物的功能。

5.1 靜態(tài)代理

????JAVA靜態(tài)代理是指由程序員創(chuàng)建或工具生成的代理類,這個(gè)類在編譯期就已經(jīng)是確定了的,存在的。
????典型的靜態(tài)代理模式一般包含三類角色:

(1)抽象角色:它的作用是定義一組行為規(guī)范。抽象角色一般呈現(xiàn)為接口(或抽象類),這些接口(或抽象類)中定義的方法就是待實(shí)現(xiàn)的。

(2)真實(shí)角色:實(shí)現(xiàn)了抽象角色所定義的行為。真實(shí)角色就是個(gè)普通的類,它需要實(shí)現(xiàn)抽象角色定義的那些接口。

(3)代理角色:代表真實(shí)角色的角色。根據(jù)上面代理的定義,我們可以知道代理角色需要至少完成(或?qū)崿F(xiàn))真實(shí)角色的功能。為了完成這一使命,那么代理角色也需要實(shí)現(xiàn)抽象角色所定義的行為(即代理類需要實(shí)現(xiàn)抽象角色所定義的接口),并且在實(shí)現(xiàn)接口方法的時(shí)候需要調(diào)用真實(shí)角色的相應(yīng)方法。

圖 5-1 靜態(tài)代理

· 特點(diǎn):需要手動(dòng)生成代理類,并在實(shí)現(xiàn)接口方法的時(shí)候調(diào)用真實(shí)類的方法。

· 缺點(diǎn):
? ? ? ? · 代理類依賴于真實(shí)類。在編譯期就已經(jīng)確定代理類和真實(shí)類的關(guān)系。
? ? ? ? · 一個(gè)真實(shí)類對(duì)應(yīng)一個(gè)代理類,導(dǎo)致類數(shù)量膨脹。

5.2 動(dòng)態(tài)代理

????動(dòng)態(tài)代理是在運(yùn)行期利用JVM的反射機(jī)制生成代理類,這里是直接生成類的字節(jié)碼(JDK動(dòng)態(tài)代理技術(shù)是在運(yùn)行時(shí)直接生成類的字節(jié)碼,并載入到虛擬機(jī)執(zhí)行的。這里不存在class文件的),然后通過類加載器載入JAVA虛擬機(jī)執(zhí)行?,F(xiàn)在主流的JAVA動(dòng)態(tài)代理技術(shù)的實(shí)現(xiàn)有兩種:一種是JDK自帶的,就是我們所說的JDK動(dòng)態(tài)代理,另一種是開源社區(qū)的一個(gè)開源項(xiàng)目CGLIB。

5.2.1 JDK動(dòng)態(tài)代理

5.2.1.1 實(shí)現(xiàn)

? ? · JDK動(dòng)態(tài)代理的實(shí)現(xiàn)是在運(yùn)行時(shí),根據(jù)一組接口定義,使用Proxy、InvocationHandler等工具類去生成一個(gè)代理類和代理類實(shí)例。這兩個(gè)類都在jdk的反射包java.lang.reflect下面。Proxy是個(gè)工具類,有了它就可以為接口生成動(dòng)態(tài)代理類了。

圖 5-2 JDK動(dòng)態(tài)代理

? ? · 生成的代理類$Proxy0對(duì)外只提供一個(gè)構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)接受一個(gè)InvocationHandler實(shí)例h,這個(gè)構(gòu)造函數(shù)的邏輯非常簡(jiǎn)單,就是調(diào)用父類的構(gòu)造函數(shù),將參數(shù)h賦值給對(duì)象字段h。最終就是把所有的方法實(shí)現(xiàn)都分派到InvocationHandler實(shí)例h的invoke方法上。所以JDK動(dòng)態(tài)代理的接口方法實(shí)現(xiàn)邏輯是完全由InvocationHandler實(shí)例的invoke方法決定的。

5.2.1.2 步驟

(1)定義一個(gè)接口,即需要代理的接口

public interface MyIntf {
?????void helloWorld();
}

(2)定義處理類,實(shí)現(xiàn)InvocationHandler接口。只有一個(gè)待實(shí)現(xiàn)的invoke(Objectproxy,Methodmethod,Object[]args)方法,proxy表示動(dòng)態(tài)代理類實(shí)例,method表示調(diào)用的方法,args表示調(diào)用方法的參數(shù)。在實(shí)際應(yīng)用中,invoke方法就是我們實(shí)現(xiàn)業(yè)務(wù)邏輯的入口。

public class MyInvocationHandler implements InvocationHandler {
?????@Override
?????public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
?????????System.out.println(method);
?????????return null;
????}
}

(3)利用Proxy.newProxyInstance(ClassLoader,Class<?>,InvocationHandler)創(chuàng)建代理類。

public class ProxyTest {
????public static void main(String[] args) { ????
????????System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
? ? ? ? MyIntf proxyObj = ????????(MyIntf)Proxy.newProxyInstance(MyIntf.class.getClassLoader(),new Class[]{MyIntf.class},new MyInvocationHandler());? ? ? ? ? ? ? ?
????????proxyObj.helloWorld();
????}
}?

5.2.1.3 生成的代理類源碼

public final class $Proxy0 extends Proxy implements MyIntf{
????private static Methodm0;
????privatestaticMethodm1;
????privatestaticMethodm2;
????privatestaticMethodm3;
????static{
????????try{
????????????m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);
????????????m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{Class.forName("java.lang.Object")});
????????????m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);
????????????m3=Class.forName("com.tuniu.distribute.openapi.common.annotation.MyIntf").getMethod("helloWorld",newClass[0]);
????????????return;
????????}catch(NoSuchMethodException localNoSuchMethodException){
????????????throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
????????}catch(ClassNotFoundException localClassNotFoundException){
????????????throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
????????}
????}
????public $Proxy0 (InvocationHandler paramInvocationHandler){
????????super(paramInvocationHandler);
????}
????public final void helloWorld(){
????????try{
????????????this.h.invoke(this,m3,null);
????????????return;

????????}catch(Error | RuntimeException localError){
????????????throw localError;
????????}catch(Throwable localThrowable){
????????????throw new UndeclaredThrowableException(localThrowable);
????????}
????}
????// 后面省略equals(),hashCode(),toString()三個(gè)方法的代碼,因?yàn)檫@三個(gè)方法和helloWorld()方法非常相似
}

5.2.1.4 原理

? ? 從上面生成的代理類源碼可以看出,在$Proxy0類中,利用Java反射技術(shù)獲取Target接口中的方法。

5.2.2 CGLIB動(dòng)態(tài)代理

5.2.2.1 實(shí)現(xiàn)

? ? · 實(shí)現(xiàn)類可以不用實(shí)現(xiàn)任何接口,使用字節(jié)碼增強(qiáng)器Enhancer類創(chuàng)建代理類。

? ? · 代理類繼承業(yè)務(wù)類,并對(duì)方法強(qiáng)化處理從而實(shí)現(xiàn)代理。

5.2.2.2 步驟

(1)查找目標(biāo)類素有非final的public方法定義
(2)將方法轉(zhuǎn)換為字節(jié)碼
(3)將組成的字節(jié)碼裝換為class對(duì)象。
(4)實(shí)現(xiàn)MethodInterceptor接口,作為攔截器。利用其intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy)方法,作為回調(diào)入口。在方法的內(nèi)部主要調(diào)用的methodProxy.invokeSuper,執(zhí)行的原始類的方法。
? ? ? ? ? ? ·obj:表示要進(jìn)行增強(qiáng)的對(duì)象;

? ? ? ? ? ? ·method:表示要被攔截的方法;

? ? ? ? ? ? ·objects:表示要被攔截方法的參數(shù);

? ? ? ? ? ? ·methodProxy:表示要觸發(fā)父類的方法對(duì)象。
(5)利用Enhance生成代理類。

5.2.2.3 原理

? ? 利用Java字節(jié)碼編輯類庫ASM操作字節(jié)碼實(shí)現(xiàn)。

5.2.3 對(duì)比兩種動(dòng)態(tài)代理

·JDK動(dòng)態(tài)代理:基于Java反射機(jī)制實(shí)現(xiàn),必須要實(shí)現(xiàn)了接口的業(yè)務(wù)類才生成代理對(duì)象。

·CGLIB動(dòng)態(tài)代理:基于ASM機(jī)制實(shí)現(xiàn),通過生成業(yè)務(wù)類的子類作為代理類。

·JDK Proxy的優(yōu)勢(shì):
????最小化依賴關(guān)系、代碼實(shí)現(xiàn)簡(jiǎn)單、簡(jiǎn)化開發(fā)和維護(hù)、JDK原生支持,比CGLIB更加可靠,隨JDK版本平滑升級(jí)。而字節(jié)碼類庫通常需要進(jìn)行更新以保證在新版Java上能夠使用。

·基于CGLIB的優(yōu)勢(shì):
????無需實(shí)現(xiàn)接口,達(dá)到代理類無侵入,只操作關(guān)心的類,而不必為其他相關(guān)類增加工作量。高性能。

圖 5-3 兩種動(dòng)態(tài)代理的對(duì)比

6 Spring AOP

6.1 概念和作用

? ? AOP(Aspect Oriented Programming: 面向切面編程)能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任(例如事務(wù)處理、日志管理、權(quán)限控制)封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可拓展性和可維護(hù)性。

6.2 原理

? ? 基于動(dòng)態(tài)代理實(shí)現(xiàn),且依賴于IOC,只對(duì)Bean有效。

6.3 相關(guān)概念

(1)Aspect 切面,一個(gè)關(guān)注點(diǎn)的模塊化
(2)Advice 通知,“切面”對(duì)某個(gè)“連接點(diǎn)”的動(dòng)作。
? ? ? ? 分類:
? ? ? ? ? ? · 前置通知 Before
? ? ? ? ? ? · 后置通知 After
? ? ? ? ? ? · 返回后通知 AfterReturning
? ? ? ? ? ? · 異常通知 AfterThrowing
? ? ? ? ? ? · 環(huán)繞通知 Around
(3)Joinpoint 連接點(diǎn),程序執(zhí)行過程中的某一行為
(4)Pointcut 切入點(diǎn),決定通知作用于哪個(gè)連接點(diǎn),集合
(5)Target Object 目標(biāo)對(duì)象,被切面通知的對(duì)象
(6)Aop Proxy Aop代理,有JDK和CGLIB兩種
(7)Advisor 決定攔截那些方法,內(nèi)部需定義Advice。

6.4 AOP 配置方式

????Spring 1.2?基于接口的配置:最早的 Spring AOP 是完全基于幾個(gè)接口的,想看源碼的同學(xué)可以從這里起步。

????Spring 2.0?schema-based 配置:Spring 2.0 以后使用 XML 的方式來配置,使用 命名空間?<aop />

????Spring 2.0?@AspectJ 配置:使用注解的方式來配置,這種方式感覺是最方便的,還有,這里雖然叫做?@AspectJ,但是這個(gè)和 AspectJ 其實(shí)沒啥關(guān)系。

6.4.1 基于接口配置

6.4.1.1 基本步驟

(1)定義目標(biāo)接口和其實(shí)現(xiàn)類

圖6-1?定義目標(biāo)接口和其實(shí)現(xiàn)類

(2)定義Advice

圖6-2 定義Advice

(3)在spring配置文件中定義ProxyFactoryBean

圖6-3?在spring配置文件中定義ProxyFactoryBean

6.4.1.2 攔截器配置

????在上面的配置中,配置攔截器的時(shí)候,interceptorNames 除了指定為 Advice,是還可以指定為 Interceptor 和 Advisor 的。

(1)Advice
? ??攔截器的粒度只控制到了類級(jí)別,類中所有的方法都進(jìn)行了攔截。

(2)Advisor
? ??它內(nèi)部需要指定一個(gè) Advice,Advisor 決定該攔截哪些方法,攔截后需要完成的工作還是內(nèi)部的 Advice 來做。

圖6-4 Advisor配置

(3)Interceptor
? ? 類似JDK動(dòng)態(tài)代理中的處理類的invoke方法。

圖6-5?Interceptor配置

6.4.1.3 autoproxy自動(dòng)代理

????上述方法有個(gè)共同的問題,那就是我們得為每個(gè) bean 都配置一個(gè)代理,之后獲取 bean 的時(shí)候需要獲取這個(gè)代理類的 bean 實(shí)例(如 (UserService) context.getBean("userServiceProxy")),這顯然非常不方便,不利于我們之后要使用的自動(dòng)根據(jù)類型注入。

用autoproxy包中的BeanNameAutoProxyCreator代替ProxyFactoryBean。

圖6-6? 自動(dòng)代理
圖6-7? 自動(dòng)代理主類

6.4.2 基于注解

6.4.2.1 maven依賴(springboot 環(huán)境下)

<dependency>
?????<groupId>org.springframework.boot</groupId>
?????<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

6.4.2.2 步驟

(1)開啟注解,使用 @EnableAspectJAutoProxy

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
?}

一旦開啟了上面的配置,那么所有使用 @Aspect 注解的 bean 都會(huì)被 Spring 當(dāng)做用來實(shí)現(xiàn) AOP 的配置類,我們稱之為一個(gè) Aspect。

(2)配置切入點(diǎn)@Pointcut

? ? 由如下幾種方式:

? ? ·?@Pointcut("execution(* transfer(..))")? 正則表達(dá)式匹配
? ? ·?@Pointcut("within(com.javadoop.springaoplearning.service..*)")?指定所在類或所在包下面的方法(Spring AOP 獨(dú)有)
? ? · @Pointcut("execution( .*(..)) && @annotation(com.javadoop.annotation.Subscribe)")?方法上具有特定的注解
? ? ·?@Pointcut("bean(*Service)")?匹配 bean 的名字(Spring AOP 獨(dú)有)
? ? 注意點(diǎn):上面匹配中,通常 "." 代表一個(gè)包名,".." 代表包及其子包,方法參數(shù)任意匹配使用兩個(gè)點(diǎn) ".."

@Aspect
public class SystemArchitecture{
????// web 層
????@Pointcut("within(com.javadoop.web..*)")
????public void inWebLayer(){
????}
????// service 層
????@Pointcut("within(com.javadoop.service..*)")
????public void inServiceLayer(){
????}
????// dao 層
????@Pointcut("within(com.javadoop.dao..*)")
????public void inDataAccessLayer(){
????}
????// service 實(shí)現(xiàn),注意這里指的是方法實(shí)現(xiàn),其實(shí)通常也可以使用bean(*ServiceImpl)
????@Pointcut("execution(* com.javadoop..service.*.*(..))")
????public void businessService(){
????}
????// dao 實(shí)現(xiàn)
????@Pointcut("execution(* com.javadoop.dao.*.*(..))")
????public void dataAccessOperation(){
????}
}

(3)配置Advice

@Aspect
public class AdviceExample{
????// 這里會(huì)用到我們前面說的 SystemArchitecture
????// 下面方法就是寫攔截 "dao層實(shí)現(xiàn)"
????@Before("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
????public void doAccessCheck(){
????// ... 實(shí)現(xiàn)代碼
????}

????// 當(dāng)然,我們也可以直接"內(nèi)聯(lián)"Pointcut,直接在這里定義 Pointcut
????// 把 Advice 和 Pointcut 合在一起了,但是這兩個(gè)概念我們還是要區(qū)分清楚的
????@Before("execution(* com.javadoop.dao.*.*(..))")
????public void doAccessCheck(){
????// ... 實(shí)現(xiàn)代碼
????}
????@AfterReturning("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
????publicvoiddoAccessCheck(){
????// ...
????}
????@AfterReturning( pointcut="com.javadoop.aop.SystemArchitecture.dataAccessOperation()", returning="retVal")
????publicvoiddoAccessCheck(Object retVal){
????????// 這樣,進(jìn)來這個(gè)方法的處理時(shí)候,retVal 就是相應(yīng)方法的返回值,是不是非常方便
????????// ... 實(shí)現(xiàn)代碼
????}

????// 異常返回
????@AfterThrowing("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
????publicvoiddoRecoveryActions(){
????// ... 實(shí)現(xiàn)代碼
????}
????@AfterThrowing( pointcut="com.javadoop.aop.SystemArchitecture.dataAccessOperation()", throwing="ex")
????public void doRecoveryActions(DataAccessException ex){
????// ... 實(shí)現(xiàn)代碼
????}
????// 注意理解它和 @AfterReturning 之間的區(qū)別,這里會(huì)攔截正常返回和異常的情況
????@After("com.javadoop.aop.SystemArchitecture.dataAccessOperation()")
????public void doReleaseLock(){
????????// 通常就像 finally 塊一樣使用,用來釋放資源。
????????// 無論正常返回還是異常退出,都會(huì)被攔截到
????}
????// 感覺這個(gè)很有用吧,既能做 @Before 的事情,也可以做 @AfterReturning 的事情
????@Around("com.javadoop.aop.SystemArchitecture.businessService()")
????public Object doBasicProfiling(ProceedingJoinPoint pjp)throwsThrowable{
????// start stopwatchObject
? ? retVal = pjp.proceed();
????// stop stopwatchreturnretVal;
? ? }
}

· 此外,Spring 提供了非常簡(jiǎn)單的獲取入?yún)⒌姆椒?,使?org.aspectj.lang.JoinPoint 作為 Advice 的第一個(gè)參數(shù)即可,如:

@Before("com.javadoop.springaoplearning.aop_spring_2_aspectj.SystemArchitecture.businessService()")
public void logArgs(JoinPoint joinPoint){? ?
????System.out.println("方法執(zhí)行前,打印入?yún)ⅲ?+ Arrays.toString(joinPoint.getArgs()));
}

注意:第一,必須放置在第一個(gè)參數(shù)上;第二,如果是 @Around,我們通常會(huì)使用其子類 ProceedingJoinPoint,因?yàn)樗?procceed()/procceed(args[]) 方法。

6.4.3?schema-based 配置

? ??是 Spring 2.0 以后提供的基于 <aop /> 命名空間的 XML 配置。這里說的 schema-based 就是指基于 aop 這個(gè) schema。

6.5 AOP源碼分析

圖6-8 AOP相關(guān)接口圖
圖6-9 AOP源碼分析 a
圖6-10 AOP源碼分析 b

7 Spring MVC

7.1 MVC模型

圖7-1 MVC模型

7.2 web環(huán)境中的IOC環(huán)境

(1)由ContextLoaderListener 啟動(dòng)根上下文(IOC容器)。
(2)由WebApplicationContext 啟動(dòng)子上下文

7.3 工作流程圖

圖7-2 MVC流程圖

(1)用戶向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求被Spring 前端控制Servelt DispatcherServlet捕獲;

(2)執(zhí)行DispatcherServlet的doservice()方法,執(zhí)行其中的doDispatcher()方法。

(3)DispatcherServlet對(duì)請(qǐng)求URL進(jìn)行解析,得到請(qǐng)求資源標(biāo)識(shí)符(URI)。然后根據(jù)該URI,調(diào)用HandlerMapping(處理器映射器,會(huì)去查找一個(gè)HashMap類型的handlerMapper,key為URL,value為handler)獲得該Handler配置的所有相關(guān)的對(duì)象(包括Handler對(duì)象以及Handler對(duì)象對(duì)應(yīng)的攔截器),最后以HandlerExecutionChain對(duì)象的形式返回;

(4)?DispatcherServlet 根據(jù)獲得的Handler,選擇一個(gè)合適的HandlerAdapter。(附注:如果成功獲得HandlerAdapter后,此時(shí)將開始執(zhí)行攔截器的preHandler(...)方法)

(5)?提取Request中的模型數(shù)據(jù),填充Handler入?yún)ⅲ?b>開始執(zhí)行Handler(Controller)。在填充Handler的入?yún)⑦^程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:

(6)?Handler執(zhí)行完成后,向DispatcherServlet?返回一個(gè)ModelAndView對(duì)象;

(7)根據(jù)返回的ModelAndView,選擇一個(gè)適合的ViewResolver(必須是已經(jīng)注冊(cè)到Spring容器中的ViewResolver)返回給DispatcherServlet?;

(8)ViewResolver 結(jié)合Model和View,來渲染視圖

(9)將渲染結(jié)果返回給客戶端。

7.4?請(qǐng)求處理方法Action

????Spring MVC中每個(gè)控制器中可以定義多個(gè)請(qǐng)求處理方法,我們把這種請(qǐng)求處理方法簡(jiǎn)稱為Action,每個(gè)請(qǐng)求處理方法可以有多個(gè)不同的參數(shù),以及一個(gè)多種類型的返回結(jié)果。

Action常見返回值種類:

? ? ·ModelAndView
? ? ·Model
? ? ·Map 包含模型的屬性
? ? ·View
? ? ·String 視圖名稱
? ? ·void

7.4.1 String

????默認(rèn)如果action返回String,此時(shí)的String為視圖名稱,會(huì)去視圖解析器的設(shè)定的目錄下查找,查找的規(guī)則是:URL= prefix前綴+視圖名稱+suffix后綴組成。

????如果方法聲明了注解@ResponseBody ,將內(nèi)容或?qū)ο笞鳛?HTTP 響應(yīng)正文返回,并調(diào)用適合HttpMessageConverter的Adapter轉(zhuǎn)換對(duì)象,寫入輸出流。些時(shí)的String不再是路徑而是內(nèi)容。

7.4.2 Void

????當(dāng)方法沒有返回值時(shí),方法中并未指定視圖的名稱,則默認(rèn)視圖的名稱為方法名.

????當(dāng)方法的返回值為void,但輸出流中存在輸出內(nèi)容時(shí),則不會(huì)去查找視圖,而是將輸入流中的內(nèi)容直接響應(yīng)到客戶端,響應(yīng)的內(nèi)容類型是純文本。

7.4.3 ModelAndView

?????在舊的Spring MVC中ModelAndView使用頻率非常高,它可以同時(shí)指定須返回的模型與視圖對(duì)象或名稱。

@RequestMapping("/action35")

? ? public ModelAndView action35()

? ? {

? ? ? ? //1只指定視圖

? ? ? ? //return new ModelAndView("/bar/index");


? ? ? ? //2分別指定視圖與模型

? ? ? ? //Map<String, Object> model=new HashMap<String,Object>();

? ? ? ? //model.put("message", "ModelAndView action35");

? ? ? ? //return new ModelAndView("/bar/index",model);


? ? ? ? //3同時(shí)指定視圖與模型

? ? ? ? //return new ModelAndView("/bar/index","message","action35 ModelAndView ");


? ? ? ? //4分開指定視圖與模型

? ? ? ? ModelAndView modelAndView=new ModelAndView();

? ? ? ? //指定視圖名稱

? ? ? ? modelAndView.setViewName("/bar/index");

? ? ? ? //添加模型中的對(duì)象

? ? ? ? modelAndView.addObject("message", "<h2>Hello ModelAndView</h2>");

? ? ? ? return modelAndView;

? ? }?

7.4.4 Map

????當(dāng)返回結(jié)果為Map時(shí),相當(dāng)于只是返回了Model,并未指定具體的視圖,返回視圖的辦法與void是一樣的,即URL= prefix前綴+控制器路徑+方法名稱?+suffix后綴組成。

7.4.5 Model

????該接口Model定義在包org.springframework.ui下,model對(duì)象會(huì)用于頁面渲染,視圖路徑使用方法名,與void類似。

7.4.6 自定義類型

????當(dāng)返回值為自定義類型時(shí)Spring會(huì)把方法認(rèn)為是視圖名稱,與返回值為void的類似辦法處理URL,但頁面中獲得數(shù)據(jù)比較麻煩。在action上添加@ResponseBody注解則返回的是自定義類型本身,而非視圖,Spring會(huì)選擇一個(gè)合適的方式解析對(duì)象,默認(rèn)是json。

8 Spring JDBC

8.1 模板模式

(1)定義一個(gè)抽象類,定義模板方法TemplateMethod。

(2)使用:設(shè)計(jì)具體類,集成模板類,如JdbcTemplate。

8.2 JdbcTemplate

8.2.1 設(shè)計(jì)原理

? ? JdbcTemplate繼承了基類JdbcAccessor和接口類JdbcOperation。

(1)JdbcAccessor:對(duì)DataSource數(shù)據(jù)源進(jìn)行管理和配置。

(2)JdbcOperation:定義通過JDBC操作數(shù)據(jù)庫的基本操作方法。JdbcTemplate對(duì)接口方法進(jìn)行實(shí)現(xiàn),如execute方法、query方法、update方法等。

8.2.2 使用

(1)使用基于回調(diào)函數(shù),在回調(diào)函數(shù)中嵌入用戶對(duì)數(shù)據(jù)庫進(jìn)行操作的代碼或者由spring來生成。

(2)直接使用JdbcTemplate的execute(String sql)方法完成數(shù)據(jù)庫操作。

8.3 操作對(duì)象

? ? 如MappingSqlQuery,可以直接返回object,是簡(jiǎn)單的ORM實(shí)現(xiàn)。

9 Spring 事務(wù)

9.1 分類

9.1.1 編程式事務(wù)控制

????·自己手動(dòng)控制事務(wù)
? ? ·? ?Jdbc代碼:Conn.setAutoCommite(false); ?//設(shè)置手動(dòng)控制事務(wù)
????????Hibernate代碼:Session.beginTransaction(); ???//開啟一個(gè)事務(wù)
? ? · 粒度:可以是方法中的某幾行。
? ? · 特點(diǎn):比較靈活,但開發(fā)起來比較繁瑣:每次都要開啟、提交、回滾.

9.1.2 聲明式事務(wù)控制

? ? · Spring提供了對(duì)事務(wù)的管理
? ? · 核心實(shí)現(xiàn): 基于AOP
? ? · 粒度:整個(gè)方法
? ? · 事務(wù)管理器類:
? ?????????? Jdbc技術(shù):DataSourceTransactionManager
? ? ? ? ? ? ?Hibernate技術(shù):HibernateTransactionManager
? ? · 配置方式:
? ? ? ? ? ? XML
? ? ? ? ? ? @Transactional注解
? ? · 注意點(diǎn)
? ???????????事物是程序運(yùn)行如果沒有錯(cuò)誤,會(huì)自動(dòng)提交事物,如果程序運(yùn)行發(fā)生異常,則會(huì)自動(dòng)回滾。 如果使用了try捕獲異常時(shí).一定要在catch里面手動(dòng)回滾。

9.2 事務(wù)傳播行為

·支持當(dāng)前事務(wù)

(1)PROPAGATION_REQUIRED--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。

(2)PROPAGATION_SUPPORTS--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。

(3)PROPAGATION_MANDATORY--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。?

·不支持當(dāng)前事務(wù)

(4)]PROPAGATION_REQUIRES_NEW--新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。?

(5)PROPAGATION_NOT_SUPPORTED--以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。?

(6)PROPAGATION_NEVER--以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。

·其他

(7)PROPAGATION_NESTED-創(chuàng)建并非嵌套

10 Spring 遠(yuǎn)端調(diào)用

Spring 遠(yuǎn)端調(diào)用的實(shí)現(xiàn):

(1)HTTP調(diào)用器
? ? ? ? · 基于HTTP協(xié)議,使用HttpInvokerProxyFactoryBean實(shí)現(xiàn)。使用AOP封裝。
? ? ? ? · 對(duì)象序列化傳輸,接收響應(yīng)后反序列化。

(2)Hssion/Burlap
? ? ? ? · hession 使用二進(jìn)制協(xié)議
? ? ? ? · Burlap 基于XML
? ? ? ? 但是都是基于http協(xié)議設(shè)計(jì)

(3)Spring RMI
? ? ? ? 基于TCP/IP協(xié)議,使用序列化傳輸對(duì)象。

11 Spring代碼

11.1 依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.qian</groupId>

<artifactId>qian-spring</artifactId>

<version>0.0.1-SNAPSHOT</version>

<dependencies>

<!-- 引入Spring-AOP等相關(guān)Jar -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

<version>3.0.6.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>3.0.6.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</artifactId>

<version>3.0.6.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-orm</artifactId>

<version>3.0.6.RELEASE</version>

</dependency>

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjrt</artifactId>

<version>1.6.1</version>

</dependency>

<dependency>

<groupId>aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.5.3</version>

</dependency>

<dependency>

<groupId>cglib</groupId>

<artifactId>cglib</artifactId>

<version>2.1_2</version>

</dependency>

</dependencies>

</project>

11.2 配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="

? ? ? ? http://www.springframework.org/schema/beans

? ? ? ? http://www.springframework.org/schema/beans/spring-beans.xsd

? ? ? ? http://www.springframework.org/schema/context

? ? ? ? http://www.springframework.org/schema/context/spring-context.xsd

? ? ? ? http://www.springframework.org/schema/aop

? ? ? ? http://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="userEntity" class="com.qian.entity.UserEntity" />

</beans>

11.3 啟動(dòng)

public class SpringTest {

????public static void main(String[] args) {

????????ClassPathXmlApplicationContext applicationContext = new ????????ClassPathXmlApplicationContext("applicationContext.xml");

????????UserEntity userEntity = (UserEntity) applicationContext.getBean("userEntity");

????????System.out.println(userEntity);

????}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容