-
設(shè)值注入,通過(guò)set的方式注入,自動(dòng)的調(diào)用類的set方法給屬性賦值
查看全部 -
通過(guò)xml的方式將bean加載到容器,通過(guò)xml來(lái)獲取bean
查看全部 -
類自動(dòng)檢測(cè)及Bean的注冊(cè):
<context:component-scan base-package="org.example"/>
查看全部 -
Spring注解:@Configuration,@Bean,@Import,@DependsOn
@Component是一個(gè)通用注解,可以作為元注解,可用于任何bean
@Repository -DAO層
@Service - Service層
@controller -Controller層
查看全部 -
Bean的生命周期:定義,初始化,使用,銷毀
//初始化?配置init-method <bean?id="initBean"?class="examples.ExampleBean"?init-method="init"></bean> //銷毀?配置destroy-method <bean?id="destroyBean"?class="examples.ExampleBean"?destroy-method="cleanup"></bean>
查看全部 -
Spring 注入方式:設(shè)值注入,構(gòu)造注入
查看全部 -
接口:
面向接口編程:
接口是用于隱藏具體實(shí)現(xiàn)和實(shí)現(xiàn)多態(tài)性的組件
接口實(shí)現(xiàn)的變動(dòng)不影響各層間的調(diào)用,
風(fēng)情層次級(jí)調(diào)用關(guān)系,每層只向外提供一組件功能接口,各層僅依賴接口而非實(shí)現(xiàn)類
查看全部 -
課程內(nèi)容:
什么是框架?
Spring簡(jiǎn)介
IOC配置注解
Bean配置注解
AOP配置注解,AspectJ,API
查看全部 -
ioc:控制反轉(zhuǎn),控制權(quán)的轉(zhuǎn)移,應(yīng)該是程序本身不負(fù)責(zé)依賴對(duì)象的創(chuàng)建和維護(hù),而是由外部容器負(fù)責(zé)創(chuàng)建和維護(hù)。
di:依賴注入是一種實(shí)現(xiàn)方式
查看全部 -
Spring中把所有的對(duì)象稱為bean
查看全部 -
Spring的Ioc是通過(guò)外部容器來(lái)創(chuàng)建和維護(hù)對(duì)象, 而不是程序自己本身創(chuàng)建, 依賴注入是其實(shí)現(xiàn)方式, 本質(zhì)是為了實(shí)現(xiàn)降低耦合度的目的.
查看全部 -
旮旯查看全部
-
元注解,@component
查看全部 -
Maven
(1)是一個(gè)可以通過(guò)一小段描述信息來(lái)管理項(xiàng)目的構(gòu)建、報(bào)告和文檔的軟件項(xiàng)目管理工具
(2)作用:在文件中添加相應(yīng)的配置,maven就可以自動(dòng)下載對(duì)應(yīng)的jar包;該jar包依賴的jar包也會(huì)被自動(dòng)下載下來(lái);可以直接通過(guò)他打包壓縮文件或jar項(xiàng)目
1°下載jar包
Maven項(xiàng)目有一個(gè)pom.xml文件,只要添加對(duì)應(yīng)的配置,就可以自動(dòng)下載jar包。
在代碼中,對(duì)于一個(gè)<dependency>結(jié)點(diǎn),其中有
項(xiàng)目名:<groupId>junit</groupId>
項(xiàng)目模塊:<artifactId>junit</artifactId>
項(xiàng)目版本:<version>4.8.2</version>
來(lái)對(duì)應(yīng)的下載jar包
2°尋找和下載依賴的jar包
3°熱部署,熱依賴
在web項(xiàng)目已經(jīng)運(yùn)行時(shí),修改代碼可以直接被web服務(wù)器接受,不需要重啟服務(wù)器或重新部署代碼;可以直接通過(guò)maven打包war或jar項(xiàng)目
?
pom.xml解析
xsi全名:xml schema instance 即xml架構(gòu)實(shí)例
xmlns是web.xml文件用到的命名空間
xmlns:xsi是指web.xml遵守xml規(guī)范
xsi:schemaLocation是指具體用到的schema資源?
properties指常量,在pom的其它地方可以直接引用
dependencies 依賴關(guān)系
build構(gòu)建配置
plugins插件列表
depositories倉(cāng)庫(kù)配置
distributionManagement 分發(fā)配置
profile“用戶配置文件”是針對(duì)每個(gè)帳戶的數(shù)據(jù)存儲(chǔ)
?
Nginx
Nginx同Apache一樣都是一種WEB服務(wù)器?;赗EST架構(gòu)風(fēng)格,以統(tǒng)一資源描述符(Uniform Resources Identifier, URI)或者統(tǒng)一資源定位符(Uniform Resources Locator, URL)作為溝通依據(jù),通過(guò)HTTP協(xié)議提供各種網(wǎng)絡(luò)服務(wù)。
Apache是重量級(jí)的、不支持高并發(fā)、性能差,作為替代品,Nginx應(yīng)運(yùn)而生。
Nginx是一款自由的、開(kāi)源的、高性能的HTTP服務(wù)器和反向代理服務(wù)器;同時(shí)也是一個(gè)IMAP、POP3、SMTP代理服務(wù)器;Nginx可以作為一個(gè)HTTP服務(wù)器進(jìn)行網(wǎng)站的發(fā)布處理,另外Nginx可以作為反向代理進(jìn)行負(fù)載均衡的實(shí)現(xiàn)。
?
JavaBean
1.JavaBean是使用Java語(yǔ)言開(kāi)發(fā)的一個(gè)可重用的組件,在開(kāi)發(fā)中可以使用JavaBean減少重復(fù)代碼,使整個(gè)代碼的開(kāi)發(fā)更簡(jiǎn)潔
2.一個(gè)類中只包含屬性、setter、getter方法,那么這種類就成為簡(jiǎn)單JavaBean。
簡(jiǎn)單JavaBean的名詞:
(1)VO:與簡(jiǎn)單Java對(duì)象對(duì)應(yīng),專門用于傳遞值的操作上
(2)POJO:簡(jiǎn)單Java對(duì)象
(3)TO:傳輸對(duì)象,進(jìn)行遠(yuǎn)程傳輸時(shí),對(duì)象所在的類必須實(shí)現(xiàn)java.io.Serializable接口。
3.Web項(xiàng)目中的目錄:
WEB-INF:Web目錄中最安全的文件夾,保存各種類、第三方j(luò)ar包、配置文件
Web.xml:Web的部署描述符
4.xml文件,表示可擴(kuò)展標(biāo)記語(yǔ)言,是一種很像HTML的標(biāo)記語(yǔ)言,旨在傳輸數(shù)據(jù)而不是顯示數(shù)據(jù)。
5.web.xml
web.xml文件并不是web工程必須的。
web.xml文件是用來(lái)初始化配置信息:比如Welcome頁(yè)面、servlet、servlet-mapping、filter、listener、啟動(dòng)加載級(jí)別等。
?
JSON
JSON是一種取代XML的數(shù)據(jù)結(jié)構(gòu),和xml相比,它更小巧但描述能力卻不差,由于它的小巧所以網(wǎng)絡(luò)傳輸數(shù)據(jù)將減少更多流量從而加快速度,
那么,JSON到底是什么?
JSON就是一串字符串 只不過(guò)元素會(huì)使用特定的符號(hào)標(biāo)注。
{} 雙括號(hào)表示對(duì)象
[] 中括號(hào)表示數(shù)組
"" 雙引號(hào)內(nèi)是屬性或值
: 冒號(hào)表示后者是前者的值(這個(gè)值可以是字符串、數(shù)字、也可以是另一個(gè)數(shù)組或?qū)ο?
所以 {"name": "Michael"} 可以理解為是一個(gè)包含name為Michael的對(duì)象
而[{"name": "Michael"},{"name": "Jerry"}]就表示包含兩個(gè)對(duì)象的數(shù)組
當(dāng)然了,你也可以使用{"name":["Michael","Jerry"]}來(lái)簡(jiǎn)化上面一部,這是一個(gè)擁有一個(gè)name數(shù)組的對(duì)象
?
GSON
GSON是Google提供的用來(lái)在Java對(duì)象和JSON數(shù)據(jù)之間進(jìn)行映射的Java類庫(kù)??梢詫⒁粋€(gè)Json字符轉(zhuǎn)成一個(gè)Java對(duì)象,或者將一個(gè)Java轉(zhuǎn)化為Json字符串。
GSON的創(chuàng)建方式:
(1)Gson gson = new gson();
(2)通過(guò)GsonBuilder()配置多種配置
Gson gson = new GsonBuilder().配置方法().create();
方法:
public String toJson(Object obj):將對(duì)象轉(zhuǎn)換為JSON字符串?
public T fromJson(String jsonStr, T.class):將JSON字符串轉(zhuǎn)換為java對(duì)象
?
servlet
實(shí)質(zhì)就是運(yùn)行在 Web 應(yīng)用服務(wù)器上的 Java 程序,與普通 Java 程序不同,它是位于 Web 服務(wù)器內(nèi)部的服務(wù)器端的 Java 應(yīng)用程序,可以對(duì) Web 瀏覽器或其他 HTTP 客戶端程序發(fā)送的請(qǐng)求進(jìn)行處理。
? Servlet的框架是由兩個(gè)Java包組成:javax.servlet和javax.servlet.http. 在javax.servlet包中定義了所有的Servlet類都必須實(shí)現(xiàn)或擴(kuò)展的的通用接口和類.在javax.servlet.http包中定義了采用HTTP通信協(xié)議的HttpServlet類.
? 廣義的servlet指實(shí)現(xiàn)了Servlet接口的類,一般情況下Servlet用來(lái)拓展基于HTTP協(xié)議的Web服務(wù)器。編寫一個(gè) Servlet 其實(shí)就是按照 Servlet 規(guī)范編寫一個(gè) Java 類。
Servlet沒(méi)有main方法,它的對(duì)象的運(yùn)行需要Servlet容器(Web容器)的支持,它的創(chuàng)建、使用、銷毀都由Servlet容器進(jìn)行管理(如Tomcat)。Servlet被部署到Servlet容器中,由容器來(lái)實(shí)例化和調(diào)方法。
有了 Servlet 之后,用戶通過(guò)單擊某個(gè)鏈接或者直接在瀏覽器的地址欄中輸入 URL 來(lái)訪問(wèn) Servlet ,Web 服務(wù)器接收到該請(qǐng)求后,并不是將請(qǐng)求直接交給 Servlet ,而是交給 Servlet 容器。Servlet 容器實(shí)例化 Servlet ,調(diào)用 Servlet 的一個(gè)特定方法對(duì)請(qǐng)求進(jìn)行處理, 并產(chǎn)生一個(gè)響應(yīng)。這個(gè)響應(yīng)由 Servlet 容器返回給 Web 服務(wù)器,Web 服務(wù)器包裝這個(gè)響應(yīng),以 HTTP 響應(yīng)的形式發(fā)送給 Web 瀏覽器。
Servlet是和HTTP協(xié)議緊密聯(lián)系的,它可以處理HTTP協(xié)議相關(guān)的所有內(nèi)容。這也是Servlet應(yīng)用廣泛的原因之一?
Servlet的主要作用功能:接受從瀏覽器發(fā)送過(guò)來(lái)的HTTP請(qǐng)求(request),并返回HTTP響應(yīng)(response)。這個(gè)工作是在service方法中完成的。要獲取客戶端提交的數(shù)據(jù)需通過(guò)request,要想容器輸出數(shù)據(jù)需通過(guò)response。
?
Servlet工作原理解析:一個(gè)HTTP請(qǐng)求的執(zhí)行過(guò)程:
客戶端發(fā)出請(qǐng)求http://localhost:8080/xxx
根據(jù)Web.xml文件的配置,找到<url-pattern>對(duì)應(yīng)的<servlet-mapping>
讀取<servlet-mapping>中<servlet-name>的值
找到<servlet-name>對(duì)應(yīng)的<servlet-class>
找到該class并加載執(zhí)行該class
?
在Web容器中,Servlet主要經(jīng)歷4個(gè)階段:
(1)加載Servlet
(2)初始化Servlet init()方法
(3)處理請(qǐng)求service()方法
(4)處理完成destory()方法
?
開(kāi)發(fā)Servlet程序:
(a)定義一個(gè)類HelloServlet,并讓該類去實(shí)現(xiàn)javax.servlet.Servlet接口;
(b)實(shí)現(xiàn)Servlet接口中的init,service,destory等方法.
?
配置 Servlet:
上面編寫好的 HelloServlet 類僅僅是一個(gè)普通的實(shí)現(xiàn)類而已,而現(xiàn)在我想要它運(yùn)行在我自己的 Tomcat 服務(wù)器中,所以應(yīng)該通知 Tomcat 服務(wù)器來(lái)管理我的 HelloServlet 類
?
Servlet 提供處理請(qǐng)求的方法:
Servlet 即實(shí)現(xiàn)了 Servlet 接口的類,當(dāng)我們創(chuàng)建一個(gè)自定義類,實(shí)現(xiàn) Servlet 接口 的時(shí)候,會(huì)發(fā)現(xiàn)有 5 個(gè)方法需要重寫,有init【初始化】,destroy【銷毀】,service【服務(wù)】,ServletConfig【Servlet配置】,getServletInfo【Serlvet信息】。
這樣做的話,我們每次都需要實(shí)現(xiàn) 5 個(gè)方法,太麻煩了!
我們可以直接繼承 HttpServlet 類,該類已經(jīng)默認(rèn)實(shí)現(xiàn)了 Servlet 接口中的所有方法,在編寫 Servlet 的時(shí)候,你只需要重寫你需要的方法就好了。
對(duì)于每次訪問(wèn)請(qǐng)求,Servlet引擎都會(huì)創(chuàng)建一個(gè)新的HttpServletRequest請(qǐng)求對(duì)象和一個(gè)新的HttpServletResponse響應(yīng)對(duì)象,然后將這兩個(gè)對(duì)象作為參數(shù)傳遞給它調(diào)用的Servlet的service()方法,service方法再根據(jù)請(qǐng)求方式分別調(diào)用doXXX方法。
?
GET 和 POST 的區(qū)別:
要知道,GET 和 POST 都是請(qǐng)求方式
GET:
瀏覽器器地址欄:http://localhost/test.html?name=wmyskxz&sex=male
這里提交了兩個(gè)參數(shù),一個(gè)是name屬性值為wmyskxz,另一個(gè)是sex屬性值為male,這是一種直接的請(qǐng)求方式,在請(qǐng)求資源后面跟上 ? 符號(hào)與參數(shù)連接,其他的參數(shù)使用 & 符號(hào)連接。
缺點(diǎn):
1.暴露請(qǐng)求信息,不安全
2.請(qǐng)求信息不能超過(guò)1kb,可傳輸?shù)男畔⒂邢蓿荒苌蟼鲌D片
POST:
瀏覽器地址欄:http://localhost/test.html#
優(yōu)點(diǎn):
1.隱藏了請(qǐng)求信息,較安全(但仍可以通過(guò)相關(guān)工具訪問(wèn)到數(shù)據(jù))
2.POST 方式?jīng)]有限制請(qǐng)求的數(shù)據(jù)大小,可以做圖片的上傳
但并不是所有的數(shù)據(jù)都需要使用 POST 請(qǐng)求來(lái)完成,事實(shí)上,GET 請(qǐng)求方式會(huì)比 POST 請(qǐng)求更快,當(dāng)數(shù)據(jù)小并且安全性要求不是那么高的時(shí)候,GET 仍然是很好的選擇.(并且 GET 相較 POST 簡(jiǎn)單)
?
MVC 模式
MVC 是一種分層的設(shè)計(jì)模式 。
M 代表 模型(Model)
模型是什么呢? 模型就是數(shù)據(jù),就是dao,bean
V 代表 視圖(View)
視圖是什么呢? 就是網(wǎng)頁(yè), JSP,用來(lái)展示模型中的數(shù)據(jù)
C 代表 控制器(controller)
控制器是什么? 控制器的作用就是把不同的數(shù)據(jù)(Model),顯示在不同的視圖(View)上。
?
HTTPServlet
當(dāng)Web容器接收到某個(gè)Servlet請(qǐng)求時(shí),Servlet把請(qǐng)求封裝成一個(gè)HttpServletRequest對(duì)象,然后把對(duì)象傳給Servlet的對(duì)應(yīng)的服務(wù)方法.
HTTP的請(qǐng)求方式包括DELETE(刪),GET(查),OPTIONS,POST(增),PUT(改)和TRACE,在HttpServlet類中分別提供了相應(yīng)的服務(wù)方法DoGet()等
HttpServlet的功能:讀取Http請(qǐng)求的內(nèi)容。
請(qǐng)求流程如下:
1)Web客戶向Servlet容器發(fā)出Http請(qǐng)求;
2)Servlet容器解析Web客戶的Http請(qǐng)求;
3)Servlet容器創(chuàng)建一個(gè)HttpRequest對(duì)象,在這個(gè)對(duì)象中封裝Http請(qǐng)求信息;
4)Servlet容器創(chuàng)建一個(gè)HttpResponse對(duì)象;
5)Servlet容器調(diào)用HttpServlet的service方法,把HttpRequest和HttpResponse對(duì)象作為service方法的參數(shù)傳給HttpServlet對(duì)象;
6)HttpServlet調(diào)用HttpRequest的有關(guān)方法,獲取HTTP請(qǐng)求信息;
7)HttpServlet調(diào)用HttpResponse的有關(guān)方法,生成響應(yīng)數(shù)據(jù);
8)Servlet容器把HttpServlet的響應(yīng)結(jié)果傳給Web客戶。
?
Tomcat
(1)輕量級(jí)Web應(yīng)用服務(wù)器(是一個(gè)Servlet/JSP容器,Servlet/JSP程序需要運(yùn)行在web容器上)。通俗來(lái)講,萬(wàn)維網(wǎng)的本質(zhì)是超文本文檔(HTML文檔)組成的一個(gè)通過(guò)超級(jí)鏈接互相訪問(wèn)交互網(wǎng)絡(luò),當(dāng)甲計(jì)算機(jī)上的文檔A通過(guò)超鏈接訪問(wèn)乙計(jì)算器上的文檔B,B必須放在Web服務(wù)器才能被訪問(wèn)
(2)應(yīng)用程序是一個(gè)WAR(WebArchive)文件,根目錄下有Html和JSP文件或包含這兩種文件的目錄,還有一個(gè)WEB-INF目錄。WEB-INF目錄下有一個(gè)web.xml文件和一個(gè)classes目錄,web.xml是這個(gè)應(yīng)用的配置文件,classes目錄下則包含編譯好的Servlet類和Jsp或Servlet所依賴的其它類(如JavaBean)
(3)還具有傳統(tǒng)的Web服務(wù)器的功能:處理Html頁(yè)面
?
單元測(cè)試
1.斷言
(1)斷言:也就是所謂的assertion,是jdk1.4后加入的新功能。
(2)它主要使用在代碼開(kāi)發(fā)和測(cè)試時(shí)期,用于對(duì)某些關(guān)鍵數(shù)據(jù)的判斷,如果這個(gè)關(guān)鍵數(shù)據(jù)不是你程序所預(yù)期的數(shù)據(jù),程序就提出警告或退出。java使用assert作為一個(gè)關(guān)鍵字
(3)語(yǔ)法
語(yǔ)法1:assert expression;???????????????
//expression代表一個(gè)布爾類型的表達(dá)式,如果為真,就繼續(xù)正常運(yùn)行,如果為假,程序退出
語(yǔ)法2:assert expression1 : expression2;??????????????????
//expression1是一個(gè)布爾表達(dá)式,expression2是一個(gè)基本類型或者Object類型,如果expression1為真,則程序忽略expression2繼續(xù)運(yùn)行;如果expression1為假,則運(yùn)行expression2,然后退出程序。
(4)斷言功能是用于軟件的開(kāi)發(fā)和測(cè)試的,也就是說(shuō),刪去斷言的那部分語(yǔ)句后,你程序的結(jié)構(gòu)和運(yùn)行不應(yīng)該有任何改變,千萬(wàn)不要把斷言當(dāng)成程序中的一個(gè)功能來(lái)使用
2.Junit
(1)是一個(gè)Java語(yǔ)言的單元測(cè)試框架
(2)為什么要使用Junit:
通常一個(gè)項(xiàng)目中有成千上萬(wàn)的方法,以前一般的做法是寫一些測(cè)試代碼看輸出結(jié)果,然后由自己來(lái)判斷結(jié)果是否正確,使用JUnit的好處就是這個(gè)結(jié)果是否正確的判斷是由JUnit來(lái)完成的。我們只要關(guān)注結(jié)果是否正確就可以了。測(cè)試框架可以幫助我們對(duì)編寫的程序進(jìn)行有目的性的測(cè)試,減少代碼中的bug,使用斷言機(jī)制直接將預(yù)期結(jié)果與實(shí)際結(jié)果對(duì)比,確保對(duì)結(jié)果的可預(yù)知性。
(3)JUint包含:junit.jar和hamcrest-core.jar:設(shè)置匹配性規(guī)則的一個(gè)框架,可以有效增強(qiáng)JUnit測(cè)試的能力。
(4)用IDEA進(jìn)行單元測(cè)試(對(duì)src的包下的已經(jīng)存在的類進(jìn)行):
在src目錄下創(chuàng)建一個(gè)新的包test,再創(chuàng)建一個(gè)類,右鍵選中在按SHIFT+CTRL+ALT+S,選擇Modules的Dependencies右邊的綠色加號(hào),在IDEA的安裝目錄下找到lib下的兩個(gè)jar包:Junit-4.12和hamcrest-core-1.3。
然后可以通過(guò)@Test注釋(需要導(dǎo)包org.junit.Test,將普通方法修飾為測(cè)試方法)來(lái)添加斷言方法,如:
@Test
public void testAdd() {
??? assertEquals(6, new Caculate().add(4,2));
}
其中assertEquals()方法是org.junit.Assert中的方法,可以用靜態(tài)導(dǎo)入(import static org.junit.Assert.*),如果期望值和實(shí)際值一致則沒(méi)問(wèn)題,如果不一致會(huì)拋出AssertError錯(cuò)誤。
注意所有方法都是public void修飾的
(5)Junit通過(guò)@BeforeClass @AfterClass @Before @After可以調(diào)用其他方法,其中快捷鍵ALT+INSERT中出現(xiàn)的setUp Method(@Before)為每個(gè)測(cè)試方法運(yùn)行前運(yùn)行的方法,tearDown Method(@After)為每個(gè)測(cè)試方法運(yùn)行后運(yùn)行的方法
(6)Test有兩個(gè)屬性:@Test(expected=xx.class) ,如@Test(expected = ArithmeticException.class)則當(dāng)被除數(shù)為0是不會(huì)拋出算數(shù)異常(預(yù)期已經(jīng)拋出該異常)
和@Test(timeout=毫秒) 超過(guò)該時(shí)間則結(jié)束
(7)@Ingore修飾的方法不會(huì)被執(zhí)行
(8)通過(guò)測(cè)試套件來(lái)組織測(cè)試類一起運(yùn)行
@RunWith(Suite.class)
@Suite.SuiteClasses({TaskTest1.class, TaskTest2.class})
public class SuiteTest {
????? //…
}
該類是一個(gè)空類,通過(guò)@RunWith(Suite.class)來(lái)開(kāi)始批量測(cè)試,用@Suit.SuiteClasses來(lái)放入需要進(jìn)行測(cè)試的測(cè)試類
(9)參數(shù)化設(shè)置,通過(guò)@RunWith(Parameterized.class)實(shí)現(xiàn)
@Runwith(Parameterized.class)
public class ParameterTest {
????? int expected = 0;
????? int input1 = 0;
????? int input2 = 0;
?
????? @Parameters
????? public static Collection<Object[]> t() {
?????????? return Arrays.asList(new Object[][] {
???????????????? {3,1,2},
{4,2,2}
});
}
?
public ParameterTest(int expected, int input1, int input2) {
????? this.expected = expected;
????? this.input1 = input1;
????? this.input2 = input2;
}
?
@Test
public void testAdd() {
????? assertEquals(expected, new Calculate().add(input1,input2));
}
}
先定義存放數(shù)據(jù)的變量,然后聲明一個(gè)返回值為Collection的靜態(tài)方法來(lái)存放數(shù)據(jù),然后提供一個(gè)構(gòu)造方法,最后寫一個(gè)測(cè)試方法。注意@RunWith()注釋中的是Parameterized的class對(duì)象
?
JDBC
JDBC(Java DataBase Connectivity)是Java和數(shù)據(jù)庫(kù)的橋梁
編程步驟:
(1)裝載數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)并進(jìn)行初始化
1°導(dǎo)入jar包,如mysql-connector-java-5.0.8-bin.jar
2°初始化驅(qū)動(dòng)類com.mysql.jdbc.Driver
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
(需要捕獲異常)
(2)建立JDBC和數(shù)據(jù)庫(kù)之間的連接
Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/exam?characterEncoding=UTF-8", "root", "admin");
包括三個(gè)參數(shù)(URL,數(shù)據(jù)庫(kù)的用戶名,數(shù)據(jù)庫(kù)的密碼)
其中URL包括jdbc:mysql://數(shù)據(jù)庫(kù)的主機(jī):端口/要操作的數(shù)據(jù)庫(kù)的名稱?編碼方式
Connection接口必須在用完關(guān)閉
(3)獲取Statement或PreparedStatement接口,來(lái)執(zhí)行sql語(yǔ)句
Statement容易出錯(cuò),不常用
增加 刪除 修改:
String sql = “update t_course set course_name=? where courese_id=?”;???
PreparedStatement ps = c.prepareStatement(sql);
ps.setString(1, “chinese”);
ps.setInt(2, 5);
ps.executeUpdate();????? //增刪改都使用Update ;可以有返回值,標(biāo)識(shí)多少條數(shù)據(jù)受到了影響
查詢:
String sql = “select * from tb_user where id=?”;? //其中?是一個(gè)占位符,后面來(lái)對(duì)它賦值
PreparedStatement ps = c.prepareStatement(sql);
ps.setLong(1,1L);???? //給第一個(gè)占位符賦值為1L
ResultSet rs = ps.executeQuery();???
當(dāng)數(shù)據(jù)量比較大時(shí),可以使用批量添加
for(int i=1; i<100; i++) {
pstmt.setInt(1, 8000+i);
pstmt.setString(2, "趙_"+i);
???? pstmt.addBatch();
????? //批量更新
???? if(i%10 == 0) {
???? ???? pstmt.executeBatch();
???? }
}
(4)執(zhí)行sql語(yǔ)句,如果有結(jié)果,將它返回集合ResultSet,并對(duì)結(jié)果進(jìn)行處理
ResultSet rs = ps.executeQuery();???
while(resultSet.next()) {?????? //遍歷結(jié)果
????? System.out.println(resultSet.getString("Name"));????? //根據(jù)括號(hào)中的屬性值得到結(jié)果
????? System.out.println(resultSet.getInt("age"));
}
(5)釋放資源(從里到外)
if(rs != null) {
????? try {
rs.close();
}catch (SQLException e) {
??? ????? e.printStackTrace();
}
}
if(ps != null) {
try {
rs.close();
}catch (SQLException e) {
???? ???? e.printStackTrace();
}
}
if(c != null) {
try {
rs.close();
}catch (SQLException e) {
???? ???? e.printStackTrace();
}
}
?
加密算法
1.哈希算法:哈希算法是單向的,可以將任何大小的數(shù)據(jù)轉(zhuǎn)化為定長(zhǎng)的密文,而且無(wú)法被反向計(jì)算。另外,即使數(shù)據(jù)源只改動(dòng)了一丁點(diǎn),哈希的結(jié)果也會(huì)完全不同。這樣的特性使得它非常適合用于保存密碼。作為哈希函數(shù)的一種,MD5(消息摘要算法)被廣泛應(yīng)用,但是它所產(chǎn)生的哈希值非常弱,容易通過(guò)字典攻擊和暴力攻擊破解。
2.密碼加鹽:鹽是在獲取密碼哈希值過(guò)程中添加到密碼的一段隨機(jī)序列,它能夠防止通過(guò)預(yù)先計(jì)算的彩虹表破解。每個(gè)用戶創(chuàng)建屬于自己的鹽,這樣一來(lái),即使用戶的密碼相同,通過(guò)加鹽后的哈希值也將不同。在獲取鹽值后,將用戶的原始密碼與鹽值一起加密得到密文。同時(shí)鹽值通常和密碼哈希值一起存放在賬戶數(shù)據(jù)庫(kù)中,或者直接存為哈希字符串的一部分。當(dāng)需要驗(yàn)證用戶的密碼時(shí),需要將鹽值取出,按照之前的加密規(guī)則與密碼一起重新加密,并驗(yàn)證兩次的密文是否相同。
3.SHA(安全散列算法)和MD5相似,但是它產(chǎn)生的哈希值很強(qiáng),如SHA256算法的哈希值大小為256位。
4.PBKDF2加密算法:全稱Password-Based Key Derivation Function,屬于哈希算法。它可以使哈希函數(shù)足夠慢以阻止攻擊,但仍然足夠快以至于不會(huì)對(duì)用戶造成明顯的延遲。PBKDF2算法使用SHA256作為偽隨機(jī)函數(shù),并對(duì)密碼加鹽,同時(shí)指定迭代次數(shù)來(lái)減慢暴力破解的速度,具有很強(qiáng)的安全性。在Java中的實(shí)現(xiàn)為PBKDF2WithHmacSHA1。
?
MyBatis
1.在Java中,對(duì)數(shù)據(jù)庫(kù)的常用工具是JDBC,它的工作量大,開(kāi)發(fā)者需要先注冊(cè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)、建立數(shù)據(jù)庫(kù)連接、創(chuàng)建Statement對(duì)象來(lái)執(zhí)行sql語(yǔ)句、設(shè)置查詢參數(shù)、執(zhí)行查詢并將結(jié)果集返回ResultSet對(duì)象,解析結(jié)果集,最后還需要釋放資源。通過(guò)JDBC來(lái)訪問(wèn)數(shù)據(jù)庫(kù),每一次都需要進(jìn)行上述一些重復(fù)的繁雜的代碼。
主要缺點(diǎn)如下:
(1)? 頻繁的對(duì)數(shù)據(jù)庫(kù)創(chuàng)建和釋放連接接會(huì)造成系統(tǒng)資源的浪費(fèi)。
(2)? sql語(yǔ)句寫在代碼里,屬于硬編碼,不易進(jìn)行維護(hù)。
(3)? sql參數(shù)硬編碼,不易進(jìn)行維護(hù)。
(4)? 對(duì)結(jié)果集的解析麻煩,需要開(kāi)發(fā)者自己去讀取并生成對(duì)應(yīng)的pojo對(duì)象。
2.MyBatis對(duì)JDBC很好地進(jìn)行了封裝,解決了上述缺點(diǎn),分別如下:
(1)? 在SqlMapConfig.xml配置文件中設(shè)置數(shù)據(jù)庫(kù)連接池,通過(guò)數(shù)據(jù)庫(kù)連接池來(lái)管理數(shù)據(jù)庫(kù)。
(2)? 將sql語(yǔ)句配置在xxxmapper.xml文件中,與代碼分離。
(3)? MyBatis自動(dòng)將java對(duì)象映射給sql語(yǔ)句。
(4)? MyBatis自動(dòng)將sql語(yǔ)句的執(zhí)行結(jié)果映射給java對(duì)象
3.Mybatis使用的主要步驟(使用傳統(tǒng)Dao的開(kāi)發(fā)方式):
(1)? 導(dǎo)入依賴的jar包
(2)? 配置MyBatis核心配置配置SqlMapConfig.xml,包括:
a)使用properties導(dǎo)入連接數(shù)據(jù)庫(kù)的配置信息
b)使用environment來(lái)配置JDBC事務(wù)管理器、數(shù)據(jù)庫(kù)連接池
c)配置映射文件(將sqlSessionFactory注入到實(shí)現(xiàn)類)
(3)? 配置log4j.properties文件
(4)? 創(chuàng)建pojo類
(5)? 創(chuàng)建Dao接口
(6)? 創(chuàng)建DaoImpl實(shí)現(xiàn)類
(7)? 創(chuàng)建Mapper映射文件xxx.xml,包括sql語(yǔ)句
(8)? 進(jìn)行單元測(cè)試
4.傳統(tǒng)Dao開(kāi)發(fā)的方式是在實(shí)現(xiàn)類中注入SqlSessionFactory并通過(guò)工廠類獲取SqlSession對(duì)象,缺點(diǎn)是在實(shí)現(xiàn)類中存在大量模板方法,并且調(diào)用SqlSession方法時(shí)存在硬編碼;使用Mapper代理的方式進(jìn)行開(kāi)發(fā),只需要寫dao接口(Mapper),而不需要寫dao實(shí)現(xiàn)類,由mybatis根據(jù)dao接口和映射文件中statement的定義生成接口實(shí)現(xiàn)代理對(duì)象。
5.Mybatis使用的主要步驟(使用Mapper動(dòng)態(tài)代理的開(kāi)發(fā)方式):
(1)? 導(dǎo)入依賴的jar包
(2)? 配置MyBatis核心配置配置SqlMapConfig.xml,包括:
a)使用properties導(dǎo)入連接數(shù)據(jù)庫(kù)的配置信息
b)使用environment來(lái)配置JDBC事務(wù)管理器、數(shù)據(jù)庫(kù)連接池
c)配置映射文件
????????? i.方法1:通過(guò)配置MapperFactoryBean類,將sqlSessionFactory注入到接口???????
????????? ii.方法2使用包掃描:通過(guò)MapperScannerConfigurer類將mapper接口所在的包賦給basePackage(比方法
1更簡(jiǎn)單)
(3)? 配置log4j.properties文件
(4)? 創(chuàng)建pojo類
(5)? 創(chuàng)建Mapper接口
(6)? 創(chuàng)建xxxMapper.xml映射文件,包括sql語(yǔ)句,注意:
a)namespace必須是接口的全路徑名
b)接口的方法名必須與sql id 一致
c)接口的入?yún)⒈仨毰cparameterType類型一致
d)接口的返回值必須與resultType類型一致
(7)? 進(jìn)行單元測(cè)試
6.
(1)使用Spring:
Spring用來(lái)管理對(duì)象關(guān)系,可以根據(jù)配置文件來(lái)創(chuàng)建及組裝對(duì)象之間的依賴關(guān)系,Spring的面向切面編程能幫助我們無(wú)耦合地實(shí)現(xiàn)日志記錄、性能統(tǒng)計(jì)、安全控制等。
(2)Spring整合MyBatis步驟:
1°重新配置MaBatis的配置文件SqlMapConfig.xml,不再包含數(shù)據(jù)庫(kù)連接、數(shù)據(jù)庫(kù)連接池、SqlSessionFactory對(duì)象等內(nèi)容。
2°創(chuàng)建Spring的配置文件applicationContext.xml,將SqlMapConfig.xml中刪除的內(nèi)容交給Spring來(lái)完成。
查看全部 -
第五章 Spring AOP基本概念
主要內(nèi)容:
什么是AOP及實(shí)現(xiàn)方式
AOP基本概念
Spring中的AOP
AOP實(shí)現(xiàn)方式之Schema-based AOP(配置方式實(shí)現(xiàn))
Spring AOP API
AOP實(shí)現(xiàn)方式之AspectJ
5-1 AOP基本概念及特點(diǎn)
1.什么是AOP
(1)AOP:Aspect Oriented Programming的縮寫,意為:面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)
(2)主要的功能是:日志記錄、性能統(tǒng)計(jì)、安全控制、事務(wù)處理、異常處理等
(3)切面,是與功能垂直的,比如日志要對(duì)每一個(gè)模塊的每一個(gè)點(diǎn)處都進(jìn)行記錄
2.AOP的實(shí)現(xiàn)方式
(1)預(yù)編譯
如AspectJ
(2)運(yùn)行期動(dòng)態(tài)代理(JDK動(dòng)態(tài)代理、CGLib動(dòng)態(tài)代理)
如SpringAOP、JbossAOP
3.AOP相關(guān)概念
(1)切面Aspect:一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)可能會(huì)橫切(控制)多個(gè)對(duì)象
(2)連接點(diǎn)Joinpoint:程序執(zhí)行過(guò)程中的某個(gè)特定的點(diǎn)
(3)通知Advice:在切面的某個(gè)特定的連接點(diǎn)上(額外)執(zhí)行的動(dòng)作
(4)切入點(diǎn)Pointcut:匹配連接點(diǎn)的斷言,在AOP中通知和一個(gè)切入點(diǎn)表達(dá)式關(guān)聯(lián)
(5)引入Introduction:在不修改類代碼的前提下,為類添加新的方法和屬性(類似于編譯器將java文件編程為class文件)
(6)目標(biāo)對(duì)象Target Object:被一個(gè)或多個(gè)切面通知的對(duì)象
(7)AOP代理AOP Proxy:AOP框架創(chuàng)建的對(duì)象,用來(lái)實(shí)現(xiàn)奇恩契約(aspect contract)(包括通知方法執(zhí)行等功能)
(8)織入Weaving:把切面連接到其它的應(yīng)用程序類型或者對(duì)象上,并創(chuàng)建一個(gè)被通知的對(duì)象,分為:編譯時(shí)織入、類加載時(shí)織入、執(zhí)行時(shí)織入
4.通知Advice的類型
(1)前置通知Before advice:在某連接點(diǎn)(join point)之前執(zhí)行的通知,但不能阻止連接點(diǎn)前的執(zhí)行(除非它拋出一個(gè)異常)
(2)返回后通知After returning advice:在某連接點(diǎn)(join point)正常完成后執(zhí)行的通知
(3)返回異常后通知After throwing advice:在方法拋出異常退出時(shí)執(zhí)行的通知
(4)后通知After(finally) advice:當(dāng)某連接點(diǎn)退出時(shí)執(zhí)行的通知(不論是正常返回還是異常退出)
(5)環(huán)繞通知Around Advice:包圍一個(gè)連接點(diǎn)(join point)的通知
5.Spring框架中AOP的用途
(1)提供了聲明式的企業(yè)服務(wù),特別是EJB的替代服務(wù)的聲明
(2)允許用戶定制自己的切面,以完成OOP與AOP的互補(bǔ)使用
6.Spring的AOP實(shí)現(xiàn)
(1)純java實(shí)現(xiàn),無(wú)需特殊的編譯過(guò)程,不需要控制類加載器層次
(2)目前只支持方法執(zhí)行連接點(diǎn)(通知Spring Bean的方法執(zhí)行)
(3)不是為了提供最完整的AOP實(shí)現(xiàn)(盡管它非常強(qiáng)大);而是側(cè)重于提供一種AOP實(shí)現(xiàn)和Spring IoC容器之間的整合,用于幫助解決企業(yè)應(yīng)用中的常見(jiàn)問(wèn)題
(4)Spring AOP不會(huì)與AspectJ競(jìng)爭(zhēng),從而提供綜合全面的AOP解決方案
7.有接口和無(wú)接口的Spring AOP實(shí)現(xiàn)的區(qū)別
(1)有接口:Spring AOP默認(rèn)使用標(biāo)準(zhǔn)的JavaSE動(dòng)態(tài)代理作為AOP代理,這使得任何接口(或接口集)都可以被代理
(2)無(wú)接口:Spring AOP中也可以使用CGLIB代理(如果一個(gè)業(yè)務(wù)對(duì)象并沒(méi)有實(shí)現(xiàn)一個(gè)接口)
?
下面內(nèi)容:Schema——基于配置的AOP實(shí)現(xiàn)
5-2 配置切面aspect
1.Spring所有的切面和通知器都必須放在一個(gè)<aop:config>內(nèi)(可以配置包含多個(gè)<aop:config>元素),每一個(gè)<aop:config>可以包含pointcut,advisor和aspect元素(它們必須按照這個(gè)順序進(jìn)行聲明)
2.<aop:config>風(fēng)格的配置大量使用了Spring的自動(dòng)代理機(jī)制
3.聲明aspect要用到<aop:config>和<aop:aspect>
<aop:config>
????? <aop:aspect> id="myAspect" ref="aBean">
?????????? …
????? <aop:aspect>
<aop:config>
?
<bean id="aBean" class="…">
????? …
</bean>
?
5-3 配置切入點(diǎn)Pointcut
1.聲明
execution(public * *(..)):切入點(diǎn)為執(zhí)行所有public方法時(shí)
execution(* set*(..)):切入點(diǎn)為執(zhí)行所有set開(kāi)始的方法
execution(* com.xyz.service.AccountService.*(..)):切入點(diǎn)為執(zhí)行AccountService類中的所有方法時(shí)
execution(* com.xyz.service..(..)):切入點(diǎn)為執(zhí)行com.xyz.service包下的所有方法時(shí)
execution(* com.xyz.service…(..)):切入點(diǎn)為執(zhí)行com.xyz.service包及其子包下的所有方法時(shí)
with(com.xyz.service.*)(only in Spring AOP)
with(com.xyz.service..*)(only in Spring AOP) within用于匹配指定類型內(nèi)的方法執(zhí)行
this(com.xyz.service.AccountService) (only in Spring AOP) this用于匹配當(dāng)前AOP代理對(duì)象類型的執(zhí)行方法
等等很多,用的時(shí)候再查
2.例子
1°
<aop:config>
????? <aop:pointcut id="businessService"
//在執(zhí)行service包下的所有類的任何類型的方法時(shí),引入切入點(diǎn)
?????????? expression="execution(* com.xyz.myapp.service..(..))"/>
</aop:config>
2°
<aop:config>
????? <aop:pointcut id="businessService"
//在執(zhí)行該businessService方法時(shí),引入切入點(diǎn)
?????????? expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>
3.完整的配置
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
??????? expression="execution(* com.xyz.myapp.service..(..))"/>
?? …
</aop:aspect>
<aop:config>
?
5-4 Advice應(yīng)用(配置)(上)
1.前置通知Before advice
聲明方式:
1°
<aop:aspect id="beforeExample" ref="aBean">
????? <aop:before
?????????? pointcut-ref="dataAccessOperation"?? //聲明參考切入點(diǎn)dataAccessOperation的聲明
?????????? method="doAccessCheck"/> //調(diào)用aBean的doAccessCheck方法
????? …
</aop:aspect>
2°
<aop:aspect id="beforeExample" ref="aBean">
????? <aop:before
?????????? pointcut ="execution(* com.xyz.myapp.dao..(..))"????? //直接進(jìn)行聲明
?????????? method="doAccessCheck"/>
????? …
</aop:aspect>
2.返回后通知After returning advice
聲明方式:
<aop:aspect id="afterReturningExample" ref="aBean">
????? <aop: after-returning
?????????? pointcut-ref ="dataAccessOperation"
?????????? //returning="retVal" //可以使用returning屬性來(lái)限制返回值
?????????? method="doAccessCheck"/>
????? …
</aop:aspect>
3.返回異常后通知After throwing advice
聲明方式:
<aop:aspect id="afterThrowingExample" ref="aBean">
????? <aop: after-throwing
?????????? pointcut-ref ="dataAccessOperation"
?????????? //throwing="dataAccessEx"?? //可以使用throwing屬性來(lái)指定可被傳遞的異常的參數(shù)名稱
?????????? method="doRecoverActions"/>
????? …
</aop:aspect>
4.后通知After(finally) advice
聲明方式:
<aop:aspect id="afterFinallyExample" ref="aBean">
????? <aop: after
?????????? pointcut-ref ="dataAccessOperation"
?????????? method="doReleaseLock"/>
????? …
</aop:aspect>
?
5-5 Advice應(yīng)用(配置)(下)
1.環(huán)繞通知Around Advice
(1)通知方法的第一個(gè)參數(shù)必須是ProceedingJoinPoint類型
(2)聲明方式
<aop:aspect id="aroundExample" ref="aBean">
????? <aop: around
?????????? pointcut-ref ="businessService"
?????????? method="doBasicProfiling"/>
????? …
</aop:aspect>
(3)使用方式
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
????? //執(zhí)行業(yè)務(wù)方法前,可以有方法
????? Object retVal = pjp.proceed();??? //執(zhí)行業(yè)務(wù)方法
????? //執(zhí)行業(yè)務(wù)方法后,可以有方法
????? return retVal;
}
2.advice的參數(shù)
通過(guò)在xml配置,可以將實(shí)現(xiàn)類的參數(shù)傳給環(huán)繞通知方法的參數(shù),進(jìn)而來(lái)使用
接口:
public interface FooService {
????? Foo getFoo(String fooName, int age);
}
實(shí)現(xiàn)類:
public class DefaultFooService implements FooService {
????? public Foo getFoo(String name, int age) {
?????????? return new Foo(name, age);
}
}
配置:
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<bean id="profiler" class="x.y.SimpleProfiler"/>
<aop:config>
<aop:aspect ref="profiler">
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
??????? expression="execution(* x.y.service.FooService.getFoo(String, int)) and args(name, age)" />
?? <aop:around pointcut-ref=" theExecutionOfSomeFooServiceMethod"
??????? method="profile"/>
</aop:aspect>
<aop:config>
環(huán)繞通知:
public calss SimpleProfiler {
????? public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
?????????? StopWatch clock = new StopWatch("Profiling for" + name + " and " + age + "");
?????????? try {
???????????????? clock.start(call.toShortString());
???????????????? return call.proceed();
}finally {
????? clock.stop();
????? System.out.println(clock.prettyPrint());
}
}
}
?
5-6 Introductions(配置)
1.簡(jiǎn)介允許一個(gè)切面來(lái)聲明一個(gè)實(shí)現(xiàn)指定接口的通知對(duì)象(即一個(gè)聲明了通知的切面,該通知實(shí)現(xiàn)了指定接口),并且提供了一個(gè)接口實(shí)現(xiàn)類來(lái)代表這些對(duì)象
2.它由<aop:aspect>中的<aop:declare-parents>元素聲明,該元素用于聲明所匹配的類型擁有一個(gè)新的parent(因此得名)
3.配置
<aop:aspect id="usageTrackerAspect" ref="usageTracking">
????? <aop:declare-parents???? //聲明一個(gè)通知對(duì)象
?????????? types-matching="com.xyz.myapp.service.*(+)"?? //匹配該包下的所有類的方法
?????????? implement-interface="com.xyz.myapp.service.tracking.UsageTracked" //該通知對(duì)象實(shí)現(xiàn)了指定接口
?????????? default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>???? //提供了接口實(shí)現(xiàn)類
????? <aop:before
?????????? pointcut="com.xyz.myapp.SystemArchitecture.businessService() and this(usageTracked)"
???????????????? method="recordUsage"/>
</aop:aspect>
當(dāng)匹配到符合的service的類時(shí),會(huì)為它賦予一個(gè)新的parent——UsageTracked,這樣在使用時(shí),可以對(duì)類(以新的父類接口)進(jìn)行強(qiáng)轉(zhuǎn),然后可以調(diào)用接口的方法(實(shí)現(xiàn)是指定的實(shí)現(xiàn)類的實(shí)現(xiàn))
4.使用
public void recordUsage(UsageTracked usageTracked) {
????? usageTracked.incrementUseCount();
}
?
UsageTracked usageTracked =(UsageTracked) context.getBean("myService");??
5.所有基于配置文件(schema-defined)的aspents,只支持singleton model
?
5-7 Advisors
1.advisor就像一個(gè)小的自包含的方面,只有一個(gè)advice
2.切面自身通過(guò)一個(gè)bean表示,并且必須實(shí)現(xiàn)某個(gè)advice接口,同時(shí),advisor也可以很好地利用AspectJ的切入點(diǎn)表達(dá)式
3.Spring通過(guò)配置文件中的<aop:advisor>元素支持advisor。實(shí)際使用中,大多數(shù)情況下它會(huì)和transactional advice(事務(wù)相關(guān)的advice)配合使用
4.為了定義一個(gè)advisor的優(yōu)先級(jí)以便讓advice可以有序,可以使用order屬性來(lái)定義advisor的順序
5.例子
<aop:config>
????? <aop:pointcut id="businessService"
?????????? expression="execution(* com.xyz.myapp.service..(..))"/>
????? <aop:advisor
?????????? pointcut-ref="businessService"
?????????? advice-ref="tx-advice"/>
</aop:config>
?
<tx:advice id="tx-advice">?? //事務(wù)相關(guān)
????? <tx:attributes>
?????????? <tx:method name="*" propagation="REQUIRED"/>
????? </tx"attributes>
</tx:advice>
?
第六章 Spring AOP的API介紹(了解,常用的還是在xml中進(jìn)行配置)
6-1 Spring AOP API的Pointcut、advice概念及應(yīng)用
1.Pointcut
2.Before advice
3.Throws advice
4.After Returning advice
5.Interception around advice
6.Introduction advice
7.Advisor
?
6-2 ProxyFactoryBean及相關(guān)內(nèi)容(上)
1.創(chuàng)建Spring AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean
2.(即通過(guò)引入中間層)這可以完全控制切入點(diǎn)和通知(advice)以及他們的順序
3.假如定義了一個(gè)bean id為foo的ProxyFactoryBean,那么引用foo對(duì)象時(shí),看到的將不是ProxyFactoryBean本身的實(shí)例,而是ProxyFactoryBean實(shí)現(xiàn)里getObject()方法創(chuàng)建的對(duì)象,getObject方法將創(chuàng)建一個(gè)AOP代理來(lái)包裝一個(gè)目標(biāo)對(duì)象。通過(guò)這種方式來(lái)達(dá)到代理的目的
4.
(1)使用ProxyFactoryBean或者其它IoC相關(guān)類來(lái)創(chuàng)建AOP代理的最重要好處是通知和切入點(diǎn)也可以由IoC來(lái)管理
(2)如果被代理類沒(méi)有實(shí)現(xiàn)任何借口,則使用CGLIB代理,否則使用JDK代理
(3)通過(guò)設(shè)置proxyTargetClass為true,可強(qiáng)制使用CGLIB
(4)如果目標(biāo)類實(shí)現(xiàn)了一個(gè)(或者多個(gè))接口,那么創(chuàng)建代理的類型將依賴ProxyFactoryBean的配置
(5)如果ProxyFactoryBean的proxyInterfaces屬性被設(shè)置為一個(gè)或多個(gè)全限定接口名,基于JDK的代理將被創(chuàng)建
(6)如果ProxyFactoryBean的proxyInterfaces屬性沒(méi)有被設(shè)置,但是目標(biāo)類實(shí)現(xiàn)了一個(gè)(或更多)接口,那么ProxyFactoryBean將自動(dòng)檢測(cè)這個(gè)類已將實(shí)現(xiàn)了至少一個(gè)接口,創(chuàng)建一個(gè)基于JDK的代理
5.創(chuàng)建基于接口的代理——代碼
<bean id="personTarget" class="com.mycompany.PersonImpl">
????? <property name="name" value="Tony"/>
????? <preperty name="age" value="51"/>
</bean>
?
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
????? <property name="someProperty" value="Custom string property value"/>
</bean>
?
<bean id="debugInterceptor" class="org.spring.aop.interceptor.DebugInterceptor">
</bean>
?
//不是直接把Person類賦給person,而是中間有一個(gè)代理層
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
????? <property name="proxyInterfaces" value="com.mycompany.Person"/>
?????
????? <property name="target" ref="personTarget"/>
????? <property name="interceptorNames">
?????????? <list>
???????????????? <value>myAdvisor</vlaue>
???????????????? <value>debugInterceptor</value>
?????????? </list>
????? </property>
</bean>
?
//其它bean調(diào)用時(shí)
<bean id="personUser" class="com.mycompany.PersonUser">
????? <property name="person"><ref bean="person"/></property>
</bean>
6.使用匿名內(nèi)部bean來(lái)隱藏目標(biāo)和代理之間的關(guān)系(即不用reference,直接在內(nèi)部定義bean)(推薦使用)
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
????? <property name="proxyInterfaces" value="com.mycompany.Person"/>
?????
????? <property name="target"
<bean class="com.mycompany.PersonImpl">
?? <property name="name" value="Tony"/>
?? <preperty name="age" value="51"/>
</bean>
????? <property name="interceptorNames">
?????????? <list>
???????????????? <value>myAdvisor</vlaue>
???????????????? <value>debugInterceptor</value>
?????????? </list>
????? </property>
</bean>
?
6-3 ProxyFactoryBean及相關(guān)內(nèi)容(下)
1.Proxying classes(Proxy類)
(1)前面的例子中如果沒(méi)有Person接口,則Spring會(huì)使用CGLIB代理,而不是JDK動(dòng)態(tài)代理
(2)如果想,可以強(qiáng)制在任何情況下使用CGLIB,即使有接口
(3)CGLIB代理的工作原理是在運(yùn)行時(shí)生成目標(biāo)類的子類,Spring配置這個(gè)生成的子類委托方法調(diào)用到原來(lái)的目標(biāo)
(4)子類是用來(lái)實(shí)現(xiàn)Decorator模式,織入通知
(5)CGLIB的代理對(duì)用戶是透明的,需要注意:
1°final不能被通知,因?yàn)樗鼈儾荒鼙桓采w
2°不需要把CGLIB添加到classpath中,在Spring3.2中,CGLIB被重新包裝并包含在Spring核心的JAR(即基于CGLIB的AOP就像JDK動(dòng)態(tài)代理一樣“開(kāi)箱即用”)
2.使用global advisors
用*做通配,匹配所有攔截器加入通知鏈(即實(shí)現(xiàn)Interceptor接口的),例:
<list>
????? <value>mooc*</vlaue>
</list>
3.簡(jiǎn)化的proxy定義
使用父子bean定義,以及內(nèi)部bean定義,可能回帶來(lái)更清潔和更簡(jiǎn)潔的代理定義(抽象屬性標(biāo)記父bean定義為抽象的這樣它不能被實(shí)例化)
4.使用ProxyFactory
(1)好處:使用Spring AOP而不必依賴于Spring IoC
ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();
(2)大多數(shù)情況下最佳實(shí)踐是用IoC容器創(chuàng)建AOP代理
(3)雖然可以硬編碼方式實(shí)現(xiàn),但是Spring推薦使用配置或注解方式實(shí)現(xiàn)
5.使用"auto-proxy"
(1)Spring也允許使用“自動(dòng)代理”的bean定義,它可以自動(dòng)代理選定的bean,這是建立在Spring的"bean psot processor"功能基礎(chǔ)上的(這個(gè)功能在加載bean的時(shí)候就可以修改)
(2)通過(guò)BeanNameAutoProxyCreator實(shí)現(xiàn)
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
????? <property name="beanNames" value="jdk*,onlyJdk"/>??? //自動(dòng)代理jdk開(kāi)頭的或onlyJdk的所有bean
????? <property name="interceptorNames">
?????????? <list>
???????????????? <value>myInterceptor</value>
?????????? <list>
????? <property>
</bean>
(3)通過(guò)DefaultAdvisorAutoProxyCreator實(shí)現(xiàn),則當(dāng)前IoC容器中自動(dòng)應(yīng)用來(lái)達(dá)到創(chuàng)建代理的效果,不用顯示聲明引用advisor的bean定義
?
第七章 Spring對(duì)AspectJ的支持
7-1 AspectJ介紹及Pointcut注解應(yīng)用
1.AspectJ
(1)@AspectJ的風(fēng)格類似純java注解的普通java類
(2)Spring可以使用AspectJ來(lái)做切入點(diǎn)解析
(3)AOP的運(yùn)行時(shí)仍舊是純的Spring AOP,對(duì)AspectJ的編譯器或者織入無(wú)依賴性
2.Spring中配置@AspectJ
(1)對(duì)@AspectJ支持可以使用xml或java風(fēng)格的配置
(2)確保AspectJ的aspectjweaver.jar庫(kù)包含在應(yīng)用程序(版本1.6.8或更高版本)的classpath中
1°注解
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
2°xml配置
<aop:aspectj-autoproxy/>
3.@Aspect注解
(1)@AspectJ切面使用@Aspect注解配置,擁有@Aspect的任何bean將被Spring自動(dòng)識(shí)別并應(yīng)用
(2)用@Aspect注解的類可以有方法和字段,它們也可能包括切入點(diǎn)(pointcut),通知(Advice)和引入(introduction)聲明
(3)@Aspect注解是不能夠通過(guò)類路徑自動(dòng)檢測(cè)發(fā)現(xiàn)的,所以@Aspect需要配合使用@Component注釋或者在xml配置bean,如:
1°
<bean id="myAspect" class="org.xyz.NotVeryUserfulAspect">
????? //配置aspect的屬性
</bean>
?
@Aspect
public class NotVeryUserfulAspect {
}
2°
@Component
@Aspect
public class NotVeryUserfulAspect {
}
(4)一個(gè)類中的@Aspect注解將標(biāo)識(shí)它為一個(gè)切面,并且將自己從自動(dòng)代理中排除(不會(huì)代理自己)
4.如何定義切入點(diǎn)pointcut
(1)一個(gè)切入點(diǎn)通過(guò)一個(gè)普通的方法定義來(lái)提供,并且切入點(diǎn)表達(dá)式使用@Pointcut注解,方法返回類型必須為void
如:
@Pointcut("execution(* transfer(..))")
private void anyOldTransfer() {}
定義一個(gè)名為anyOldTransfer的方法(即一個(gè)切入點(diǎn)),這個(gè)切入點(diǎn)將匹配任何名為"transfer"的方法
5.切入點(diǎn)支持哪些定義方式(哪些點(diǎn)可以定義)
execution:匹配方法執(zhí)行的連接點(diǎn)
within:限定匹配特定類型的連接點(diǎn)
this:匹配特定連接點(diǎn)的bean引用是指定類型的實(shí)例的限制
target:限定匹配特定連接點(diǎn)的目標(biāo)對(duì)象時(shí)指定類型的實(shí)例
args:限定匹配特定連接點(diǎn)的參數(shù)是指定類型的實(shí)例
@target:限定匹配特定連接點(diǎn)的類執(zhí)行對(duì)象的具有給定類型的注解
@args:限定匹配特定連接點(diǎn)實(shí)際傳入?yún)?shù)的類型具有給定類型的注解
@within:限定匹配到內(nèi)具有給定的注釋類型的連接點(diǎn)
@annotation:限定匹配特定連接點(diǎn)的主體具有給定的注解
6.組合pointcut
(1)切入點(diǎn)表達(dá)式可以通過(guò)&&、||和!進(jìn)行組合,也可以通過(guò)名字引入切入點(diǎn)表達(dá)式
(2)通過(guò)組合,可以建立更為復(fù)雜的切入點(diǎn)表達(dá)式,如:
@Pointcut("execution(public * (..))")
private void anyPublicOperation() {}
?
@Pointcut("within(com.xyz.comeapp.trading..)")
private void inTrading() {}
?
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
7.如何定義良好的pointcuts
(1)AspectJ是編譯期的AOP
(2)檢查代碼并匹配連接點(diǎn)與切入點(diǎn)的代價(jià)是昂貴的
(3)一個(gè)好的切入點(diǎn)應(yīng)該包含以下幾點(diǎn)
1°選擇特定類型的切入點(diǎn),如:execution、get、set、call、handeler
2°確定連接點(diǎn)范圍,如:within、withincode
3°匹配上下文信息,如:this、target、@annotation
?
7-2 Advice定義及實(shí)例
1.Before advice
(1)例子
1°直接定義execution表達(dá)式
@Component
@Aspect
public class MoocAspect {
????? @Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))*)
????? public void before() {
//…
}
}
在執(zhí)行com.imooc.aop.aspectj包下以Biz結(jié)尾的類的所有方法時(shí)匹配Advice
2°引用一個(gè)已經(jīng)存在的pointcut
@Component
@Aspect
public class MoocAspect {
????? @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
public void pointcut() {}
?
@Before("execution(*pointcut()")
????? public void before() {
//…
}
}
2.After returning advice
(1)有時(shí)候需要在通知體內(nèi)得到返回的實(shí)際值,可以使用@AfterReturning綁定返回值的類型
@AfterReturning(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()", returning="retVal")
public void do AccessCheck(Object retVal) {
????? //…
}
將@AfterReturning注解中的返回值在下面的方法中聲明,不確定返回值的類型則為Object
3.After throwing advice
4.After(finally) advice
(1)最終通知必須準(zhǔn)備處理正常和異常兩種返回情況,它通常用于釋放資源
5.Around advice
(1)環(huán)繞通知使用@Around注解來(lái)聲明,通知方法的第一個(gè)參數(shù)必須是ProceedingJoinPoint類型
(2)在通知內(nèi)部調(diào)用ProceedingJoinPoint的proceed()方法會(huì)導(dǎo)致執(zhí)行真正的方法,傳入一個(gè)Object[]對(duì)象,數(shù)組中的值將被作為參數(shù)傳遞給方法
?
7-3 Advice擴(kuò)展
1.給advice傳遞參數(shù)
2.Advice的參數(shù)及泛型
3.Advice參數(shù)名稱
(1)通知和切入點(diǎn)注解有一個(gè)額外的"argNames"屬性,它可以用來(lái)指定所注解的方法的參數(shù)名,如:
@Before(vlaue="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)", argNames="bean,auditable")
public void audit(Object bean, Auditable auditable) {
AuditCode code = auditable.value();
// … use code and bean
}
(2)如果第一個(gè)參數(shù)是JointPoint、ProceedingJoinPoint、JoinPoint.StaticPart,那么可以忽略它
4.Introductions
(1)允許一個(gè)切面聲明一個(gè)通知對(duì)象實(shí)現(xiàn)指定接口,并且提供了一個(gè)接口實(shí)現(xiàn)類來(lái)代表這些對(duì)象
(2)AspectJ中使用@DeclareParents來(lái)對(duì)introduction進(jìn)行注解,這個(gè)注解用來(lái)定義匹配的類型擁有一個(gè)新的parent
5.切面實(shí)例化模型
(1)這是一個(gè)高級(jí)主題
(2)"perthis"切面通過(guò)指定@Aspect注解perthis子句實(shí)現(xiàn)
(3)每個(gè)獨(dú)立的service對(duì)象執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)切面實(shí)例
(4)service對(duì)象的每個(gè)方法在第一次執(zhí)行的時(shí)候創(chuàng)建切面實(shí)例,切面在service對(duì)象失效的同時(shí)失效
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
????? private int someState;
?
????? @Before(com.xyz.myapp.SystemArchitecture.businessService())??
????? public void recordServiceUsage() {
?????????? //…
}
}
查看全部
舉報(bào)