Spring是一個很是活躍的開源框架;它是一個基於Core來構架多層JavaEE系統的框架,它的主要目地是簡化企業開發.java
Spring以一種非侵入式的方式來管理你的代碼,Spring提倡」最少侵入」,這也就意味着你能夠適當的時候安裝或卸載Springnode
到http://www.springsource.org/download下載spring,而後進行解壓縮,在解壓目錄中找到下面jar文件,拷貝到類路徑下mysql
--spring的核心類庫 在spring文檔的dist下程序員
dist\spring.jarweb
--引入的第三方類庫 都spring文檔的lib下spring
lib\jakarta-commons\commons-logging.jarsql
若是使用了切面編程(AOP),還須要下列jar文件數據庫
lib/aspectj/aspectjweaver.jar和aspectjrt.jarexpress
lib/cglib/cglib-nodep-2.1_3.jarapache
若是使用了JSR-250中的註解,如@Resource/@PostConstruct/@PreDestroy,還須要下列jar文件
lib\j2ee\common-annotations.jar
注:JSR(Java 規範請求)是指向JCP(Java Community Process)提出新增一個標準化技術規範的正式請求。任何人均可以提交JSR(Java 規範請求),以向Java平臺增添新的API和服務。JSR已成爲Java界的一個重要標準
默認狀況下是applicationContext.xml文件。能夠創建不少xml文件,工程中通常都是這樣配置的。
Spring的控制反轉:把對象的建立、初始化、銷燬等工做交給spring容器來作。由spring容器控制對象的生命週期。
步驟:
一、 在類路徑下尋找配置文件來實例化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});能夠在整個類路徑中尋找xml文件
* 經過這種方式加載。須要將spring的配置文件放到當前項目的classpath路徑下
* classpath路徑指的是當前項目的src目錄,該目錄是java源文件的存放位置。
二、 在文件系統路徑下尋找配置文件來實例化容器
ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{「d:\\beans.xml「});Spring的配置文件能夠指定多個,能夠經過String數組傳入。
注:常常用第一種方法啓動容器
<beans>
<alias name="person" alias="p"/>
<bean name="person" class="cn.itcast.aliasspring.Person"/>
</beans>
經過這樣的配置,能夠達到在一個地方命名,在多個地方使用不一樣的名字的效果。
<bean id=「personService" class="cn.itcast.bean.impl.PersonServiceImpl"/>
在配置文件中進入以下的配置:
在客戶端
HelloWorld類自己:
在控制檯打印出了」create object」
能夠看出:spring內部默認是調用了HelloWorld這個類的默認的構造函數建立對象
<bean id="personService" class="com.itcast.factory.PersonServiceFactory" factory-method="createPersonService" />
public class PersonServiceFactory {
public static PersonService createPersonService(){
return new PersonServiceImpl();
}
}
說明:
給工廠類建立了一個對象helloWorldFactory,再利用工廠對象調用工廠方法。
執行步驟爲1,3,2
以上兩種狀況是默認值,當spring容器啓動的時候建立對象
在bean有這樣一個屬性
Default 至關於false 在spring容器啓動的時候,建立對象
True 在context.getBean時建立對象
False 在spring容器啓動的時候建立對象
若是把lazy-init設置爲true,則當spring容器啓動的時候,檢測不到任何錯誤,這樣會存在很大的安全性隱患,因此通常狀況下應該設置lazy-init爲default/false。
可是若是一個bean中有一個屬性,該屬性含有大量的數據,這個時候不但願該bean過早的停留在內存中。這個時候須要用到lazy-init爲true。
在每一個Spring IoC容器中一個bean定義只有一個對象實例(共享)。
默認狀況下會在容器啓動時初始化bean,但咱們能夠指定Bean節點的lazy-init=「true」來延遲初始化bean,這時候,只有第一次獲取bean會才初始化bean。如:
<bean id="xxx" class="cn.itcast.OrderServiceBean" lazy-init="true"/>
若是想對全部bean都應用延遲初始化,能夠在根節點beans設置default-lazy-init=「true「,以下:
<beans default-lazy-init="true「 ...>
在默認狀況下放入到spring中的bean是單例的
未來service層和dao層全部的類將放入到spring容器中,因此默認狀況下這兩個層的類的實例都是單例的,因此不能把數據聲明到屬性中。若是聲明在屬性中,將會成爲共享的。
容許bean能夠被屢次實例化(使用一次就建立一個實例) . Spring不能對一個prototype bean的整個生命週期負責.這就意味着清楚prototype做用域的對象並釋聽任何prototype bean所持有的昂貴資源都是客戶端的責任。
Spring默認在啓動時將全部singleton bean提早進行實例化。提早實例化意味着做爲初始化的一部分,ApplicationContext會自動建立並配置全部的singleton bean.一般狀況下這是件好事。由於這樣在配置中有任何錯誤能當即發現。
Lazy-init=」true or false」
Lazy-init 爲false,spring容器將在啓動的時候報錯(比較好的一種方式)
Lazy-init 爲true,spring容器將在調用該類的時候出錯。
Spring初始化bean或銷燬bean時,有時須要做一些處理工做,所以spring能夠在建立和拆卸bean的時候調用bean的兩個生命週期方法。
<bean id=「foo」 class=「...Foo」
init-method=「setup」
destory-method=「teardown」/>
當foo被載入到Spring容器中時調用init-method方法。當foo從容器中刪除時調用destory-method(scope = singleton有效)
說明:
一、 init方法是由spring內部執行的
二、 只有當spring容器關閉之後才能執行destroy方法,spring容器通常狀況下是不會關閉的。只有當web容器銷燬掉的時候纔可能關閉掉,因此只要一個對象在spring容器中,在spring容器關閉以前,會一直保留。
三、 若是一個bean的配置是scope爲」prototype」,則spring容器不負責銷燬。
在context.getBean時建立對象
在context.getBean時建立對象,lazy-init爲false失效
當scpose爲prototype時,始終在context.getBean時建立對象
由於Scopse爲prototype時,這個實例就變爲多例的,lazy-init若是爲false,
一開始就建立該實例是沒有意義的,因此這時候lazy-init默認爲true;
是默認狀況
建立對象
一、 對象的建立方式
二、 對象的建立時機
三、 對象的建立的模式
四、 Init和destroy
五、 建立時機和建立模式的結合
初始化和銷燬
說明:
一、 constructor-arg表明指定的構造器函數的其中的一個參數
二、 能夠利用index,ref,value,type來指定惟一的構造器
三、 若是一個bean的配置中沒有constructor-arg屬性,則必須利用默認的構造函數建立對象。
因此在寫一個javabean的時候,應該提供屬性的setter方法,默認的構造器,帶參數的構造器
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 6 <bean id="person" class="com.itheima09.spring.di.xml.constructor.Person"> 7 <!-- 8 指定其中的一個構造器的參數 9 index 參數的下標 從0開始計算 10 type 類型 11 value 若是是基本類型,則用value賦值 12 ref 若是是引用類型,則用ref賦值 13 --> 14 <constructor-arg index="0" value="aa"></constructor-arg> 15 <constructor-arg index="1" value="2" type="java.lang.Long"></constructor-arg> 16 </bean> 17 <bean id="person1" class="com.itheima09.spring.di.xml.constructor.Person"> 18 <property name="student"> 19 <ref bean="student"/> 20 </property> 21 </bean> 22 <bean id="student" class="com.itheima09.spring.di.xml.constructor.Student"></bean> 23 </beans>
<constructor-arg index="0">
<value>張三</value>
</constructor-arg>
<constructor-arg index="1">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.Integer">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>張三</value>
</constructor-arg>
使用xml的注入方式:
簡單Bean包括兩種類型:包裝類型和String
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<!-- 基本類型,string類型 -->
<property name="age" value="20"></property>
<property name="name" value="張無忌"></property> </bean>
<bean id="person" class="com.itcast.bean.Person" />
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<property name="person" ref="person" />
</bean>
<property name="maps">
<map>
<entry key="01">
<value>map01</value>
</entry>
<entry key="02">
<value>map02</value>
</entry>
</map>
</property>
map中的<entry>的數值和<list>以及<set>的同樣,可使任何有效的屬性元
素,須要注意的是key值必須是String的。
<property name="props">
<props>
<prop key="01">prop1</prop>
<prop key="02">prop2</prop>
</props>
</property>
說明:
一、 spring容器實例化person和student兩個對象
二、 利用java的反射機制調用屬性的setter方法賦值
三、 在客戶端利用context.getBean方法把spring容器中的一個對象獲取了。
說明:
一、 啓動spring容器
二、 實例化person對象和student對象
三、 給person中的屬性賦值
四、 調用person的init方法初始化
五、 客戶端利用context.getBean獲取對象
說明:
一、 啓動spring容器
二、 實例化person對象
三、 由於person對象依賴於student對象,因此在實例化person對象的時候必須實例化student對象,因此這個時候,在student對象上的lazy-init爲true將失效。
一、 啓動spring容器
二、 實例化student
三、 在客戶端執行context.getBean方法獲取person對象
四、 實例化person對象,調用person的構造函數
五、 調用person中的setStudent方法,給person中的student賦值
六、 執行person中的init方法
七、 Person對象調用方法
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 6 <!-- 7 把person放入到spring容器中 8 --> 9 <bean id="person" class="com.itheima09.spring.di.xml.setter.Person" 10 init-method="init" 11 lazy-init="true"> 12 <!-- 13 property用來描述person的屬性 14 name屬性表明屬性的名稱 15 value屬性表明屬性的值 屬性爲基本類型 16 由於student是引用類型,因此用ref賦值 17 --> 18 <property name="pid" value="2"></property> 19 <property name="name" value="王二麻子"></property> 20 <property name="student" ref="student"></property> 21 <property name="list"> 22 <list> 23 <value>list1</value> 24 <value>list2</value> 25 <ref bean="student"/> 26 </list> 27 </property> 28 <property name="set"> 29 <set> 30 <value>set1</value> 31 <value>set2</value> 32 <ref bean="student"/> 33 </set> 34 </property> 35 <property name="map"> 36 <map> 37 <entry key="entry1"> 38 <value>entry1</value> 39 </entry> 40 <entry key="entry2"> 41 <ref bean="student"/> 42 </entry> 43 </map> 44 </property> 45 <property name="properties"> 46 <props> 47 <prop key="prop1">prop1</prop> 48 <prop key="prop2">prop2</prop> 49 </props> 50 </property> 51 </bean> 52 <!-- 53 把student放入到spring容器中 54 --> 55 <bean id="student" 56 class="com.itheima09.spring.di.xml.setter.Student"></bean> 57 </beans>
編寫一個文檔管理系統,在該系統中有以下的結構:
一、 Document:interface
readDocument
writeDocument
二、 WordDocument 是Document的實現類
readDocument
writeDocument
三、 ExcelDocument
readDocument
writerDocument
四、 PDFDocument
readDocument
writeDocument
五、 DocumentManager
Document document;
readDocument()
writeDocument()
說明:
上述的代碼是不徹底的面向接口編程
說明:
在代碼端沒有出現具體的類,徹底的面向接口編程。
在spring容器的配置文件中決定了documentManager中的接口的實現類是什麼。而這個過程和java代碼端沒有關係。
把action調用service,service調用dao用spring來完成
實現了徹底的面向接口編程,在代碼端沒有要關係一個接口的實現類是什麼。
步驟:
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 5 xmlns:context="http://www.springframework.org/schema/context" 6 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 9 http://www.springframework.org/schema/beans/spring- beans-2.5.xsd 10 11 http://www.springframework.org/schema/context 12 13 http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
這個配置隱式註冊了多個對註釋進行解析處理的處理器
AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
注: @Resource註解在spring安裝目錄的lib\j2ee\common-annotations.jar
這兩個註解的區別是:@Autowired 默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean纔會按類型裝配。
@Autowired註解是按類型裝配依賴對象,默認狀況下它要求依賴對象必須存在,若是容許null值,能夠設置它required屬性爲false。
若是咱們想使用按名稱裝配,能夠結合@Qualifier註解一塊兒使用。以下:
一、 @Resource註解和@Autowired同樣,也能夠標註在字段或屬性的setter方法上.
二、 @Resource註解默認按名稱裝配。
名稱能夠經過@Resource的name屬性指定,若是沒有指定name屬性,
指定Bean的初始化方法
指定Bean的銷燬方法
1 import java.lang.annotation.Documented; 2 import java.lang.annotation.ElementType; 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 import java.lang.annotation.Target; 6 7 @Target(ElementType.TYPE)//ClassInfo註解能夠標註在類上 8 /** 9 *RetentionPolicy.SOURCE 只能在源代碼上使用 10 RetentionPolicy.CLASS 該註解可以使用在源代碼和字節碼上 11 RetentionPolicy.RUNTIME 該註解可以使用在源代碼、字節碼、jvm中 12 */ 13 @Retention(RetentionPolicy.RUNTIME) 14 @Documented //該註解可以出如今幫助文檔中 15 public @interface ClassInfo { 16 //給該註解聲明瞭一個屬性name,默認值爲"" 17 String name() default ""; 18 }
1 import java.lang.annotation.Documented; 2 import java.lang.annotation.ElementType; 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 import java.lang.annotation.Target; 6 7 @Target(ElementType.METHOD) 8 @Retention(RetentionPolicy.RUNTIME) 9 @Documented 10 public @interface MethodInfo { 11 String value() default ""; 12 }
1 @ClassInfo(name="該班很牛") 2 public class Itheima09 { 3 @MethodInfo("表明的是java初級") 4 public void java(){ 5 6 } 7 8 @MethodInfo("java高級") 9 public void superJava(){ 10 11 } 12 }
1 import java.lang.reflect.Method; 2 3 import org.junit.Test; 4 5 /** 6 * 註解解析器 7 * @author zd 8 * 9 */ 10 public class AnnotationParse { 11 public static void parse(){ 12 Class classt = Itheima09.class; 13 //在該類上存在ClassInfo註解 14 if(classt.isAnnotationPresent(ClassInfo.class)){ 15 //從類上獲得類的註解 16 ClassInfo classInfo = (ClassInfo)classt.getAnnotation(ClassInfo.class); 17 //輸出該註解的name屬性 18 System.out.println(classInfo.name()); 19 } 20 //獲取該類的全部的方法 21 Method[] methods = classt.getMethods(); 22 for(Method method:methods){ 23 //若是該方法上存在MethodInfo註解 24 if(method.isAnnotationPresent(MethodInfo.class)){ 25 //獲取該方法上面的methodinfo註解 26 MethodInfo methodInfo = method.getAnnotation(MethodInfo.class); 27 //輸出註解中的value屬性 28 System.out.println(methodInfo.value()); 29 } 30 } 31 } 32 33 @Test 34 public void test(){ 35 AnnotationParse.parse(); 36 } 37 }
3.4.4
要導入javaee5.0
在spring的配置文件中
說明:
一、 啓動spring容器
二、 spring容器內部建立了兩個對象person和student
三、 當spring容器解析到
啓動依賴注入的註解解析器:
四、 spring容器在容器中查找全部的bean(prerson,student)
五、 看哪些bean的屬性上面是否有Resource註解
六、 若是屬性上面有該註解,再次檢查是否有name屬性
七、 若是沒有name屬性,則會把該註解標註的屬性的名稱獲取到和spring容器中的id作匹配,若是匹配成功,則賦值,若是匹配不成功,則按照類型進行匹配,若是匹配成功,則賦值,若是匹配不成功,則報錯。
八、 若是有name屬性,則把name屬性的值解析出來和spring容器中的id作匹配,若是匹配成功,則賦值,若是匹配不成功,則報錯。
九、 從上述的步驟能夠看出註解的效率比較低,xml的效率比較高,註解書寫比較簡單,xml書寫比較複雜。
按照類型匹配
按照ID匹配
註解只能應用與引用類型
說明:在指定的包及子包中掃描
一、 啓動spring容器
二、 Spring容器解析類掃描的註解解析器,在base-package指定的包及子包中查找全部的類
三、 查看哪些類上面是否含有@Component註解
四、 若是該註解的value的屬性的值爲空,則把類名的第一個字母變成小寫,做爲id值,放入到spring容器中
五、 若是該註解的value的屬性的值不爲空,則用value的屬性的值做爲id值,放入到spring容器中
六、 再次查找在spring容器中的類的全部的屬性,按照@Resource的規則給屬性賦值
使用了類掃描機制的作法,配置文件中的配置很簡單了,可是效率愈來愈低。
前面的例子咱們都是使用XML的bean定義來配置組件。在一個稍大的項目中,一般會有上百個組件,若是這些組件採用xml的bean定義來配置,顯然會增長配置文件的體積,查找及維護起來也不太方便。spring2.5爲咱們引入了組件自動掃描機制,它能夠在類路徑底下尋找標註了@Component、@Service、@Controller、@Repository註解的類,並把這些類歸入進spring容器中管理。它的做用和在xml文件中使用bean節點配置組件是同樣的。要使用自動掃描機制,咱們須要打開如下配置信息:
1、引入context命名空間 須要在xml配置文件中配置如下信息:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="cn.itcast"/>
</beans>
2、在配置文件中添加context:component-scan標籤
<context:component-scan base-package="cn.itcast"/>
其中base-package爲須要掃描的包(含子包)。
注:
一、在使用組件掃描元素時,AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor會隱式地被包括進來。 也就是說,連個組件都會被自動檢測並織入 - 全部這一切都不須要在XML中提供任何bean配置元數據。
二、功能介紹
@Service用於標註業務層組件、
@Controller用於標註控制層組件(如struts中的action)、
@Repository用於標註數據訪問組件,即DAO組件。
而@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。
配置文件中:
圖中的配置文件中,parent爲student在容器中繼承person.若是去掉person是不行的。
代理模式的英文叫作Proxy或Surrogate,中文均可譯爲」代理「,所謂代理,就是一我的或者一個機構表明另外一我的或者另外一個機構採起行動。在一些狀況下,一個客戶不想或者不可以直接引用一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用
聲明瞭真實主題和代理主題的共同接口,這樣一來在任何可使用真實主題的地方均可以是使用代理主題
代理主題角色內部含有對真實主題的引用,從而能夠在任什麼時候候操做真實主題對象;代理主題角色提供一個與真實主題角色相同的接口,以即可以在任什麼時候候均可以替代真實主題控制對真實主題的引用,負責在須要的時候建立真實主題對象(和刪除真實主題對象);代理角色一般在將客戶端調用傳遞給真實的主題以前或以後,都要執行某個操做,而不是單純地將調用傳遞給真實主題對象。
定義了代理角色所表明地真實對象
JDK的動態代理必須具有四個條件:
目標接口
目標類
攔截器
代理類
總結:一、由於利用JDKProxy生成的代理類實現了接口,因此目標類中全部的方法在代理類中都有。
二、生成的代理類的全部的方法都攔截了目標類的全部的方法。而攔截器中invoke方法的內容正好就是代理類的各個方法的組成體。
三、利用JDKProxy方式必須有接口的存在。
四、invoke方法中的三個參數能夠訪問目標類的被調用方法的API、被調用方法的參數、被調用方法的返回類型。
一、 代理對象有多少方法,方法的名稱是什麼?
由於代理對象和目標類同樣,一樣的實現了接口,因此接口中有多少方法,代理對象中就有多少個方法,名稱和接口中的方法的名稱同樣。
二、 攔截器中的invoke方法在何時執行的?
當在客戶端,代理對象調用方法的時候,進入到了invoke方法
三、 攔截器中的invoke方法中的method參數在何時傳遞的值?
當在客戶端,代理對象調用方法的時候,進入到了invoke方法,這個時候,method參數就是代理對象調用的方法。
四、 代理對象的方法體的內容是什麼?
代理對象的方法體的內容就是invoke方法體的內容
代理對象的方法體:
一、 開啓事務
二、 目標方法
三、 事務的提交
四、 代理對象的方法體就把事務和目標方法結合在一塊兒了,這樣作的目的就是爲了讓目標類的目標方法和事務的方法鬆耦合。
做用:把目標類和事務鬆耦合
攔截器把這些內容所有結合在一塊兒了。
能夠把日誌、安全性框架等做爲一個接口出現
日誌:
攔截器:
案例1:
1 package com.itheima09.jdkproxy; 2 3 public interface PersonDao { 4 public void savePerson(); 5 public void updatePerson(); 6 }
1 public class PersonDaoImpl implements PersonDao{ 2 public void savePerson() { 3 System.out.println("save person"); 4 } 5 public void updatePerson(){ 6 System.out.println("update person"); 7 } 8 }
1 public class Transaction { 2 public void beginTransaction(){ 3 System.out.println("begin transaction"); 4 } 5 public void commit(){ 6 System.out.println("commit"); 7 } 8 }
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 import org.springframework.aop.framework.ProxyFactoryBean; 5 /** 6 * 攔截器 7 * 一、把目標類和事務引入進來 8 * 二、完成invoke方法 9 * 一、開啓事務 10 * 二、執行save person操做 11 * 三、事務提交 12 * @author zd 13 */ 14 public class PersonDaoInterceptor implements InvocationHandler{ 15 private Object target; 16 private Transaction transaction; 17 18 public PersonDaoInterceptor(Object target, Transaction transaction) { 19 this.target = target; 20 this.transaction = transaction; 21 } 22 23 public Object invoke(Object proxy, Method method, Object[] args) 24 throws Throwable { 25 if(method.getName().equals("savePerson") 26 ||method.getName().equals("updatePerson")){ 27 //開啓事務 28 this.transaction.beginTransaction(); 29 //進行save person的操做 30 method.invoke(target, args);//目標對象調用方法 31 this.transaction.commit(); 32 }else{ 33 method.invoke(target, args); 34 } 35 return null; 36 } 37 }
1 import java.lang.reflect.Proxy; 2 3 import org.junit.Test; 4 5 public class PersonDaoTest { 6 @Test 7 public void testJDKProxy(){ 8 Object target = new PersonDaoImpl(); 9 Transaction transaction = new Transaction(); 10 /** 11 * 建立一個攔截器 12 */ 13 PersonDaoInterceptor interceptor = new PersonDaoInterceptor(target, transaction); 14 /** 15 * 一、目標類的類加載器 16 * 二、目標類實現的全部的接口 17 * 三、攔截器 18 */ 19 PersonDao personDao = (PersonDao)Proxy.newProxyInstance( 20 target.getClass().getClassLoader(), 21 target.getClass().getInterfaces(), interceptor); 22 personDao.updatePerson(); 23 } 24 }
1 public interface SalaryManager { 2 /** 3 * 查看工資 4 */ 5 public void showSalary(); 6 }
1 public class SalaryManagerImpl implements SalaryManager{ 2 public void showSalary() { 3 System.out.println("正在查看工資"); 4 } 5 }
1 public class Logger { 2 public void logging(){ 3 System.out.println("logging"); 4 } 5 }
1 public class Privilege { 2 private String access; 3 public String getAccess() { 4 return access; 5 } 6 public void setAccess(String access) { 7 this.access = access; 8 } 9 }
1 public class Security { 2 public void security(){ 3 System.out.println("security"); 4 } 5 }
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 public class SalaryManagerInterceptor implements InvocationHandler{ 5 private Object target; 6 private Logger logger; 7 private Security security; 8 private Privilege privilege; 9 10 public SalaryManagerInterceptor(Object target, Logger logger, 11 Security security, Privilege privilege) { 12 this.target = target; 13 this.logger = logger; 14 this.security = security; 15 this.privilege = privilege; 16 } 17 18 public Object invoke(Object proxy, Method method, Object[] args) 19 throws Throwable { 20 /** 21 * 一、開啓日誌 22 * 二、開啓安全性的框架 23 * 三、檢查權限 24 * 若是是"admin",則查看 25 * 若是不是"admin",則提示"權限不足" 26 */ 27 this.logger.logging(); 28 this.security.security(); 29 if(this.privilege.getAccess().equals("admin")){ 30 method.invoke(target, args);//調用目標方法 31 }else{ 32 System.out.println("權限不足"); 33 } 34 return null; 35 } 36 37 }
1 import java.lang.reflect.Proxy; 2 3 import org.junit.Test; 4 5 public class SalaryTest { 6 @Test 7 public void testSalary(){ 8 Object target = new SalaryManagerImpl(); 9 Logger logger = new Logger(); 10 Security security = new Security(); 11 Privilege privilege = new Privilege(); 12 privilege.setAccess("asdf"); 13 SalaryManagerInterceptor interceptor = new SalaryManagerInterceptor( 14 target, logger, security, privilege); 15 SalaryManager proxy = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), 16 target.getClass().getInterfaces(), 17 interceptor); 18 proxy.showSalary(); 19 } 20 }
一、 CGlib是一個強大的,高性能,高質量的Code生成類庫。它能夠在運行期擴展Java類與實現Java接口。
二、 用CGlib生成代理類是目標類的子類。
三、 用CGlib生成 代理類不須要接口
四、 用CGLib生成的代理類重寫了父類的各個方法。
五、 攔截器中的intercept方法內容正好就是代理類中的方法體
六、 是用字節碼加強技術產生的代理類
1 public class PersonDaoImpl{ 2 public void savePerson() { 3 System.out.println("save person"); 4 } 5 public void updatePerson(){ 6 System.out.println("update person"); 7 } 8 }
1 public class Transaction { 2 public void beginTransaction(){ 3 System.out.println("begin transaction"); 4 } 5 public void commit(){ 6 System.out.println("commit"); 7 } 8 }
1 import java.lang.reflect.Method; 2 3 import net.sf.cglib.proxy.Enhancer; 4 import net.sf.cglib.proxy.MethodInterceptor; 5 import net.sf.cglib.proxy.MethodProxy; 6 7 public class PersonDaoInterceptor implements MethodInterceptor{ 8 private Object target; 9 private Transaction transaction; 10 11 /** 12 * 產生代理類 13 * @return 14 */ 15 public Object createProxy(){ 16 Enhancer enhancer = new Enhancer(); 17 //設置代理類的父類是目標類 18 enhancer.setSuperclass(target.getClass()); 19 enhancer.setCallback(this); 20 return enhancer.create(); 21 } 22 23 public PersonDaoInterceptor(Object target, Transaction transaction) { 24 this.target = target; 25 this.transaction = transaction; 26 } 27 28 public Object intercept(Object arg0, Method method, Object[] arg2, 29 MethodProxy arg3) throws Throwable { 30 if(method.getName().equals("savePerson") 31 ||method.getName().equals("updatePerson")){ 32 this.transaction.beginTransaction(); 33 method.invoke(target, arg2); 34 this.transaction.commit(); 35 }else{ 36 method.invoke(target, arg2); 37 } 38 return null; 39 } 40 }
1 import java.lang.reflect.Proxy; 2 3 import org.junit.Test; 4 5 public class PersonDaoTest { 6 @Test 7 public void testJDKProxy(){ 8 Object target = new PersonDaoImpl(); 9 Transaction transaction = new Transaction(); 10 /** 11 * 建立一個攔截器 12 */ 13 PersonDaoInterceptor interceptor = new PersonDaoInterceptor(target, transaction); 14 15 PersonDaoImpl proxy = (PersonDaoImpl)interceptor.createProxy(); 16 proxy.savePerson(); 17 } 18 }
優勢:由於有接口,因此使系統更加鬆耦合
缺點:爲每個目標類建立接口
優勢:由於代理類與目標類是繼承關係,因此不須要有接口的存在。
缺點:由於沒有使用接口,因此係統的耦合性沒有使用JDK的動態代理好。
一、 攔截器必須實現MethodInterceptor接口
二、 在spring中的配置
總結:無論採用JDK動態代理生成代理類仍是採用CGLIB生成動態代理類。目標類中的全部方法都被攔截下來。而在哪一個方法裏作好比權限的判斷、安全性的檢查等一系列工作必須在攔截器中做相應的判斷。可是這樣的編程形式給程序的編寫帶來了必定的麻煩。
一、 在攔截器中控制哪些方法將被作權限判斷、安全性檢查等是一件比較困難的事情。
二、 這樣的代碼也會致使硬編碼,也就是說咱們必須在攔截器中寫一些權限判斷等事情,會致使攔截器中代碼量的增大,形成維護的麻煩。
JDKProxy代理 |
SpringAop |
目標對象 |
目標對象 |
攔截器類 |
切面 |
攔截器類中的方法 |
通知 |
被攔截到的目標類中方法的集合 |
切入點 |
在客戶端調用的方法(目標類目標方法) |
鏈接點 |
代理類 |
AOP代理 |
代理類的代理方法生成的過程 |
織入 |
通知根據攔截目標類中的目標方法的位置不同能夠分爲:前置通知、後置通知、最終通知、環繞通知、異常通知
3.
說明:
一、 在開發的過程當中,日誌、權限、安全性的框架、目標方法徹底是鬆耦合的
二、 在造成代理對象的方法的過程當中就把這幾個結合在一塊兒了
AOP 術語
通知:
定義:切面也須要完成工做。在 AOP 術語中,切面的工做被稱爲通知。 工做內容:通知定義了切面是什麼以及什麼時候使用。除了描述切面要完成的工做,通知還解決什麼時候執行這個工做。 Spring 切面可應用的 5 種通知類型:
Before——在方法調用以前調用通知 After——在方法完成以後調用通知,不管方法執行成功與否 After-returning——在方法執行成功以後調用通知 After-throwing——在方法拋出異常後進行通知 Around——通知包裹了被通知的方法,在被通知的方法調用以前和調用以後執行自定義的行爲
鏈接點:
定義:鏈接點是一個應用執行過程當中可以插入一個切面的點。 鏈接點能夠是調用方法時、拋出異常時、甚至修改字段時、 切面代碼能夠利用這些點插入到應用的正規流程中 程序執行過程當中可以應用通知的全部點。
切點:
定義:若是通知定義了「什麼」和「什麼時候」。那麼切點就定義了「何處」。切點會匹配通知所要織入的一個或者多個鏈接點。 一般使用明確的類或者方法來指定這些切點。 做用:定義通知被應用的位置(在哪些鏈接點)
切面:
定義:切面是通知和切點的集合,通知和切點共同定義了切面的所有功能——它是什麼,在什麼時候何處完成其功能。
引入:
引入容許咱們向現有的類中添加方法或屬性
織入:
織入是將切面應用到目標對象來建立的代理對象過程。 切面在指定的鏈接點被織入到目標對象中,在目標對象的生命週期中有多個點能夠織入
編譯期——切面在目標類編譯時期被織入,這種方式須要特殊編譯器。AspectJ的織入編譯器就是以這種方式織入切面。 類加載期——切面在類加載到 JVM ,這種方式須要特殊的類加載器,他能夠在目標類被引入應用以前加強該目標類的字節碼。AspectJ5 的 LTW 就支持這種織入方式 運行期——切面在應用運行期間的某個時刻被織入。通常狀況下,在織入切面時候,AOP 容器會爲目標對象動態的建立代理對象。Spring AOP 就是以這種方式織入切面。
在spring配置文件中聲明切面
在spring配置文件中聲明目標類
定義切面、切入點、通知
注:見6.2.3.4
說明:
一、在切面類中,沒有必要實現接口,但方法名稱要與<aop:before method=」checkSecurity」 中的checkSecurity同樣。
二、checkSecurity方法中經過JoinPoint參數能夠得到目標類的目標方法名稱、參數值等信息。
一、 沒有特殊說明的地方和前置通知是同樣的。
二、 在spring配置文件中
三、 在攔截器中的方法要和checkSecurity方法同樣,有兩個參數
JoinPoint point 能夠得到目標方法和參數值
Object val 這裏的名字要和returning=」val」中保持一致,指的是方法的返回值。
四、 returning=」val」時,通知裏能夠有返回參數,這個參數只能決定通知裏能不能拿到方法的返回值,和客戶端沒有關係。
五、 在執行目標類的目標方法中遇到異常,則不執行後置通知。
一、 沒有特殊說明的地方和前置通知同樣
二、 在spring配置文件中
其中throwing指定了傳遞異常的參數名稱
三、 在異常通知中(攔截器)中,必須是checkSecurity方法。方法中有兩個參數
JoinPoint point 能夠得到方法的名稱、參數
Throwable ex 利用ex.getMessage()能夠得到異常信息
一、 沒有特殊說明,和前置通知的配置同樣。
二、 在spring配置文件裏:
說明:在最終通知中不受異常的影響。也就是說不論目標方法執行的過程當中是否拋出異常,最終通知都將執行。
一、 沒有特殊說明和前置通知的配置保持一致。
二、 在spring文件中
三、 在環繞通知中,方法名稱爲checkSecurity。參數 類型 爲ProceedingJoinPoint。
ProceedingJoinPoint的proceed方法至關於invoke方法,調用目標類的目標方法。ProceedingJoinPoint繼承了JoinPoint類
四、 能在方法執行的先後加入額外的代碼。
說明:
說明:
一、 context.getBean時,若是該類沒有生成代理對象,則返回對象自己
二、 若是產生了代理對象,則返回代理對象
三、 若是目標類實現了接口,則採用jdkproxy生成代理對象,若是目標類沒有實現接口,則採用cglibproxy生成代理對象,而生成代理對象是由spring容器內部完成的。
表明全部的公共方法
表明全部的以set開頭的方法
表明com.xyz.service包下的AccoutService類的全部的方法
表明com.xyz.service包下的全部的類的全部的方法
表明com.xyz.service包及子包下的全部的類的全部的方法
表明com.itheima.spring.aop.xml包下的全部的類的有三個參數,第一個參數爲Long,第二個參數爲String,第三個參數爲任意類型的全部的方法
在目標方法執行以前執行。
在目標方法執行以後執行
能夠獲取目標方法的返回值
當目標方法遇到異常,不執行
不管目標方法是否遇到異常都會執行,至關於代碼中的finnaly
獲取目標方法拋出的異常
可以控制目標方法的執行
案例1springAop:(導入兩個架包:aspectjrt.jar 和aspectjweaver.jar)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 9 <!-- 10 引入目標類和切面 11 --> 12 <bean id="personDao" 13 class="com.itheima09.spring.aop.xml.transaction.PersonDaoImpl"> 14 </bean> 15 <bean id="transaction" 16 class="com.itheima09.spring.aop.xml.transaction.Transaction"> 17 </bean> 18 <!-- 19 aop:config的配置 20 --> 21 <aop:config> 22 <!-- 23 切入點表達式 24 id爲標示符 25 --> 26 <aop:pointcut 27 expression="execution(* com.itheima09.spring.aop.xml.transaction.PersonDaoImpl.*(..))" 28 id="perform"/> 29 <!-- 30 ref指向切面 31 --> 32 <aop:aspect ref="transaction"> 33 <!-- 34 前置通知 在目標方法輸出以前執行 35 method 前置通知的名字 36 pointcut-ref 指向切入點表達式 37 --> 38 <aop:before method="beginTransaction" pointcut-ref="perform"/> 39 <aop:after-returning method="commit" pointcut-ref="perform"/> 40 </aop:aspect> 41 </aop:config> 42 </beans>
1 public interface PersonDao { 2 public String savePerson(); 3 }
1 public class PersonDaoImpl{ 2 public String savePerson() { 3 System.out.println("save person"); 4 return "aaaaa"; 5 } 6 }
1 import java.lang.reflect.Method; 2 3 import org.junit.Test; 4 5 public class Transaction { 6 public void beginTransaction(){ 7 System.out.println("開啓事務"); 8 } 9 public void commit(){ 10 System.out.println("事務提交"); 11 } 12 13 @Test 14 public void test(){ 15 Class class1 = Object.class; 16 Method[] methods = class1.getMethods(); 17 for(Method method:methods){ 18 System.out.println(method.toString()); 19 } 20 } 21 }
1 import org.junit.Test; 2 import org.springframework.context.ApplicationContext; 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5 public class PersonTest { 6 @Test 7 public void testProxy(){ 8 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 9 PersonDaoImpl personDao = (PersonDaoImpl)context.getBean("personDao"); 10 personDao.savePerson(); 11 } 12 }
從配置中能夠看出,把service層全部的類當成目標類,只要service層全部的類的全部的方法拋出異常,則exceptionAspect中的異常通知就會獲取到目標方法拋出的異常,因此在這裏異常通知就是用來處理異常的,並且只有一個方法。而且該切面和全部的其餘類都是鬆耦合的。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 9 <!-- 10 把personDao,personService,personAction放入到spring容器中 11 --> 12 <bean id="personDao" class="com.itheima09.springaop.xml.ex.exception.dao.PersonDaoImpl"></bean> 13 <bean id="personService" class="com.itheima09.springaop.xml.ex.exception.service.PersonServiceImpl"> 14 <property name="personDao"> 15 <ref bean="personDao"/> 16 </property> 17 </bean> 18 <bean id="personAction" class="com.itheima09.springaop.xml.ex.exception.action.PersonAction"> 19 <property name="personService"> 20 <ref bean="personService"/> 21 </property> 22 </bean> 23 <!-- 24 引入切面 25 --> 26 <bean id="exceptionAspect" 27 class="com.itheima09.springaop.xml.ex.exception.aspect.ExceptionAspect"></bean> 28 <aop:config> 29 <aop:pointcut 30 expression="execution(* com.itheima09.springaop.xml.ex.exception.service.*.*(..))" 31 id="perform"/> 32 <aop:aspect ref="exceptionAspect"> 33 <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/> 34 </aop:aspect> 35 </aop:config> 36 </beans>
1 import com.itheima09.springaop.xml.ex.exception.service.PersonService; 2 3 public class PersonAction { 4 private PersonService personService; 5 6 public void setPersonService(PersonService personService) { 7 this.personService = personService; 8 } 9 10 public void savePerson() throws Exception{ 11 this.personService.savePerson(); 12 } 13 }
1 public class ExceptionAspect { 2 public void throwingMethod(Throwable ex){ 3 System.out.println(ex.getMessage()); 4 } 5 }
1 package com.itheima09.springaop.xml.ex.exception.aspect; 2 3 public class MyException extends Exception{ 4 public MyException(String msg) { 5 super(msg); 6 } 7 }
1 package com.itheima09.springaop.xml.ex.exception.dao; 2 3 public interface PersonDao { 4 public void savePerson() throws Exception; 5 }
1 package com.itheima09.springaop.xml.ex.exception.dao; 2 3 import com.itheima09.springaop.xml.ex.exception.aspect.MyException; 4 5 public class PersonDaoImpl implements PersonDao{ 6 public void savePerson() throws Exception{ 7 int b = 0; 8 if(b!=0){ 9 int a = 1/b; 10 }else{ 11 throw new MyException("不能除以0"); 12 } 13 System.out.println("save person"); 14 } 15 }
1 package com.itheima09.springaop.xml.ex.exception.service; 2 3 public interface PersonService { 4 public void savePerson() throws Exception; 5 }
1 package com.itheima09.springaop.xml.ex.exception.service; 2 3 import com.itheima09.springaop.xml.ex.exception.dao.PersonDao; 4 5 public class PersonServiceImpl implements PersonService{ 6 private PersonDao personDao; 7 public PersonDao getPersonDao() { 8 return personDao; 9 } 10 public void setPersonDao(PersonDao personDao) { 11 this.personDao = personDao; 12 } 13 public void savePerson() throws Exception{ 14 this.personDao.savePerson(); 15 } 16 }
1 package com.itheima09.springaop.xml.ex.exception.test; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 import com.itheima09.springaop.xml.ex.exception.action.PersonAction; 8 9 public class ExceptionTest { 10 @Test 11 public void testException() throws Exception{ 12 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 13 PersonAction personAction = (PersonAction)context.getBean("personAction"); 14 personAction.savePerson(); 15 } 16 }
一、 寫dao層和service層的類和接口
二、 自定義的註解@PrivilegeInfo
三、 註解解析器:解析目標方法上面的註解的name屬性的值
四、 寫一個權限類Privilege(name)
五、 寫一個關於權限的判斷的切面,在切面中寫一個環繞通知
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 9 <bean id="personDao" class="com.itheima09.springaop.xml.privilege.dao.PersonDaoImpl"></bean> 10 <bean id="personService" class="com.itheima09.springaop.xml.privilege.service.PersonServiceImpl"> 11 <property name="personDao"> 12 <ref bean="personDao"/> 13 </property> 14 </bean> 15 <bean id="privilegeAspect" class="com.itheima09.springaop.xml.privilege.aspect.PrivilegeAspect"> 16 </bean> 17 <aop:config> 18 <aop:pointcut 19 expression="execution(* com.itheima09.springaop.xml.privilege.service.*.*(..))" 20 id="perform"/> 21 <aop:aspect ref="privilegeAspect"> 22 <aop:around method="controlTargetMethod" pointcut-ref="perform"/> 23 </aop:aspect> 24 </aop:config> 25 </beans>
1 package com.itheima09.springaop.xml.privilege.annotation; 2 3 import java.lang.reflect.Method; 4 5 public class AnnotationParse { 6 public static String parse(Class classt,String methodName) throws Exception{ 7 String privilegeName = ""; 8 //目標方法 9 Method method = classt.getMethod(methodName); 10 //判斷目標方法上是否有PrivilegeInfo 11 if(method.isAnnotationPresent(PrivilegeInfo.class)){ 12 //獲取目標方法上面的PrivilegeInfo註解 13 PrivilegeInfo privilegeInfo = method.getAnnotation(PrivilegeInfo.class); 14 //獲取該註解的name屬性的值 15 privilegeName = privilegeInfo.name(); 16 } 17 return privilegeName; 18 } 19 }
1 package com.itheima09.springaop.xml.privilege.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target(ElementType.METHOD) 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface PrivilegeInfo { 11 String name() default ""; 12 }
1 package com.itheima09.springaop.xml.privilege.aspect; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.aspectj.lang.ProceedingJoinPoint; 7 8 import com.itheima09.springaop.xml.privilege.annotation.AnnotationParse; 9 import com.itheima09.springaop.xml.privilege.bean.Privilege; 10 11 public class PrivilegeAspect { 12 /** 13 * 該用戶可以訪問到的權限 14 */ 15 private List<Privilege> privileges = new ArrayList<Privilege>(); 16 17 public List<Privilege> getPrivileges() { 18 return privileges; 19 } 20 21 public void setPrivileges(List<Privilege> privileges) { 22 this.privileges = privileges; 23 } 24 25 /* 26 * 環繞通知 27 */ 28 public void controlTargetMethod(ProceedingJoinPoint joinPoint) throws Throwable{ 29 /** 30 * 一、獲取用戶可以訪問到的權限 31 * 二、獲取訪問目標方法的權限 32 * 三、檢查用戶的權限中是否包含目標方法的權限 33 * 若是包含 34 * 則訪問目標方法 35 * 若是不包含 36 * 則提示不能訪問 37 */ 38 //目標類的class形式 39 Class targetClass = joinPoint.getTarget().getClass(); 40 //目標方法 41 String methodName = joinPoint.getSignature().getName(); 42 //可以訪問目標方法的權限 43 String privilegeName = AnnotationParse.parse(targetClass, methodName); 44 boolean flag = false; 45 //檢查用戶的權限是否包含訪問目標方法應該具有的權限 46 for(Privilege privilege:this.privileges){ 47 if(privilege.getName().equals(privilegeName)){ 48 flag = true; 49 break; 50 } 51 } 52 if(flag){//能夠訪問目標方法 53 joinPoint.proceed();//訪問目標方法 54 }else{ 55 System.out.println("權限不足"); 56 } 57 } 58 }
1 package com.itheima09.springaop.xml.privilege.bean; 2 3 public class Privilege { 4 private String name; 5 public String getName() { 6 return name; 7 } 8 public void setName(String name) { 9 this.name = name; 10 } 11 }
1 package com.itheima09.springaop.xml.privilege.dao; 2 3 public interface PersonDao { 4 public void savePerson(); 5 public void updatePerson(); 6 }
1 package com.itheima09.springaop.xml.privilege.dao; 2 3 public class PersonDaoImpl implements PersonDao{ 4 public void savePerson() { 5 System.out.println("save person"); 6 } 7 public void updatePerson() { 8 System.out.println("update person"); 9 } 10 }
1 package com.itheima09.springaop.xml.privilege.service; 2 3 public interface PersonService { 4 public void savePerson(); 5 public void updatePerson(); 6 }
1 package com.itheima09.springaop.xml.privilege.service; 2 3 import com.itheima09.springaop.xml.privilege.annotation.PrivilegeInfo; 4 import com.itheima09.springaop.xml.privilege.dao.PersonDao; 5 6 public class PersonServiceImpl implements PersonService{ 7 private PersonDao personDao; 8 public void setPersonDao(PersonDao personDao) { 9 this.personDao = personDao; 10 } 11 @PrivilegeInfo(name="savePerson") 12 public void savePerson() { 13 this.personDao.savePerson(); 14 } 15 @PrivilegeInfo(name="updatePerson") 16 public void updatePerson() { 17 this.personDao.updatePerson(); 18 } 19 }
1 package com.itheima09.springaop.xml.privilege.test; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 import com.itheima09.springaop.xml.privilege.aspect.PrivilegeAspect; 8 import com.itheima09.springaop.xml.privilege.bean.Privilege; 9 import com.itheima09.springaop.xml.privilege.service.PersonService; 10 11 public class PrivilegeTest { 12 @Test 13 public void test(){ 14 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 15 PrivilegeAspect privilegeAspect = (PrivilegeAspect)context.getBean("privilegeAspect"); 16 /** 17 * 給用戶初始化權限值 18 */ 19 Privilege privilege1 = new Privilege(); 20 privilege1.setName("asdf"); 21 Privilege privilege2 = new Privilege(); 22 privilege2.setName("updatePerson"); 23 privilegeAspect.getPrivileges().add(privilege1); 24 privilegeAspect.getPrivileges().add(privilege2); 25 PersonService personService = (PersonService)context.getBean("personService"); 26 personService.savePerson(); 27 } 28 }
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 9 <bean id="salaryManager" class="com.itheima09.springaop.xml.salary.SalaryManagerImpl"></bean> 10 <bean id="logger" class="com.itheima09.springaop.xml.salary.Logger"></bean> 11 <bean id="security" class="com.itheima09.springaop.xml.salary.Security"></bean> 12 <bean id="privilege" class="com.itheima09.springaop.xml.salary.Privilege"> 13 <property name="access" value="afds"></property> 14 </bean> 15 <bean id="aroundClass" class="com.itheima09.springaop.xml.salary.AroundClass"></bean> 16 17 <aop:config> 18 <aop:pointcut 19 expression="execution(* com.itheima09.springaop.xml.salary.SalaryManagerImpl.*(..))" 20 id="perform"/> 21 <aop:aspect ref="logger"> 22 <aop:before method="logging" pointcut-ref="perform"/> 23 </aop:aspect> 24 <aop:aspect ref="security"> 25 <aop:before method="security" pointcut-ref="perform"/> 26 </aop:aspect> 27 <aop:aspect ref="privilege"> 28 <aop:around method="controlTarget" pointcut-ref="perform"/> 29 </aop:aspect> 30 <aop:aspect ref="aroundClass"> 31 <aop:around method="aroundMethod" pointcut-ref="perform"/> 32 </aop:aspect> 33 </aop:config> 34 </beans>
1 package com.itheima09.springaop.xml.salary; 2 3 public class Logger { 4 public void logging(){ 5 System.out.println("logging"); 6 } 7 }
1 package com.itheima09.springaop.xml.salary; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 public class Privilege { 6 private String access; 7 public String getAccess() { 8 return access; 9 } 10 public void setAccess(String access) { 11 this.access = access; 12 } 13 public Object controlTarget(ProceedingJoinPoint joinPoint) throws Throwable{ 14 Object obj = null; 15 if(this.getAccess().equals("admin")){ 16 obj = joinPoint.proceed();//調用目標方法 17 }else{ 18 System.out.println("權限不足"); 19 } 20 return obj; 21 } 22 }
1 package com.itheima09.springaop.xml.salary; 2 3 public interface SalaryManager { 4 /** 5 * 查看工資 6 */ 7 public String showSalary(); 8 }
1 package com.itheima09.springaop.xml.salary; 2 3 public class SalaryManagerImpl implements SalaryManager{ 4 public String showSalary() { 5 System.out.println("正在查看工資"); 6 return "aaaa"; 7 } 8 }
1 package com.itheima09.springaop.xml.salary; 2 3 public class Security { 4 public void security(){ 5 System.out.println("security"); 6 } 7 }
1 package com.itheima09.springaop.xml.salary; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 public class AroundClass { 6 public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{ 7 System.out.println("----------------"); 8 joinPoint.proceed(); 9 } 10 }
1 package com.itheima09.springaop.xml.salary; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class SalaryTest { 8 @Test 9 public void test(){ 10 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 11 SalaryManager salaryManager = (SalaryManager)context.getBean("salaryManager"); 12 String s = salaryManager.showSalary(); 13 System.out.println(s); 14 } 15 }
注意:@Aspectj是按照類型匹配的。
靜態代碼+動態變量 = jdbc編程。在spring中動態變量能夠用注入的形式給予。這樣的編程方式適合包裝成模板。靜態代碼構成了模板,而動態變量則是須要傳入的參數。
在spring中注入DataSource
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 6 <!-- 7 按照指定的路徑加載配置文件 8 --> 9 <bean 10 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 11 <property name="locations"> 12 <value>classpath:jdbc.properties</value> 13 </property> 14 </bean> 15 16 <bean id="dataSource" destroy-method="close" 17 class="org.apache.commons.dbcp.BasicDataSource"> 18 <property name="driverClassName" value="${jdbc.driverClassName}" /> 19 <property name="url" value="${jdbc.url}" /> 20 <property name="username" value="${jdbc.username}" /> 21 <property name="password" value="${jdbc.password}" /> 22 </bean> 23 24 <!-- 25 abstract="true" 告訴spring容器不要爲該bean建立對象 26 --> 27 <!-- 28 第一種寫法 29 --> 30 <bean id="itheima09Template" 31 class="com.itheima09.spring.jdbc.template.Itheima09Template" 32 abstract="true"> 33 <property name="dataSource"> 34 <ref bean="dataSource"/> 35 </property> 36 </bean> 37 38 39 </beans>
1 jdbc.driverClassName=com.mysql.jdbc.Driver 2 jdbc.url=jdbc\:mysql\://localhost\:3306/hibernate02 3 jdbc.username=root 4 jdbc.password=123456
1 package com.mikey.www; 2 3 import java.sql.Connection; 4 5 import javax.sql.DataSource; 6 7 import org.junit.Test; 8 import org.springframework.context.ApplicationContext; 9 import org.springframework.context.support.ClassPathXmlApplicationContext; 10 11 public class DataSourceTest { 12 @Test 13 public void testDataSource(){ 14 ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); 15 DataSource dataSource=(DataSource) context.getBean("dataSource"); 16 System.out.println(dataSource); 17 } 18 19 }
一、 基於模板的設置(爲何能夠設置成基於模板的形式)
二、 完成了資源的建立和釋放的工做
三、 簡化爲咱們對JDBC的操做
四、 完成了對JDBC的核心流程的工做,包括SQL語句的建立和執行
五、 僅須要傳遞DataSource就能夠把它實例化
六、 JdbcTemplate只須要建立一次
七、 JdbcTemplate是線程安全類
在Dao類中,用JdbcTemplate做爲屬性,用spring對JdbcTemplate進行注入。再對JdbcTemplate進行DataSource注入。
注:爲何只要對JdbcTemplate注入DataSource就能夠了?
在Dao類中,繼承JdbcDaoSupport。由於JdbcDaoSupport已經有了JdbcTemplate的引用,因此只要繼承JdbcDaoSupport就至關於有了JdbcTemplate屬性。
1 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 2 3 <property name="locations"> 4 5 <list> 6 7 <value>jdbc.properties</value> 8 9 </list> 10 11 </property> 12 13 </bean>
一、 產生緣由:在Jdbc的操做中,有不少狀況下是要將ResultSet裏的數據封裝到一個持久化Bean裏,再把持久化Bean封裝到集合中。這樣會形成大量的代碼的重複,不利於代碼重用。而RowMapper正好解決了這個問題。
二、 使用:
一、 寫一個類實現RowMapper接口
二、 在回調接口中,做爲參數進行傳入便可。
程序員再也不負責處理事務,事務處理交給spring容器來作。
程序員負責兩個內容:
一、 對錶的crud操做:目標類的目標方法
二、 告訴spring容器什麼樣的目標方法採用什麼樣的事務策略
Spring容器負責:(切面)
負責事務的處理
採用了aop技術來實現的。
說明:經過spring的事務處理架構,再經過配置文件具體的實現事務的類,就可讓spring容器知道是什麼樣的技術來操做數據庫,經過對事務狀態的判斷,經過事務的定義就能夠知道具體的目標方法採用什麼樣的事務策略來處理了。
1 jdbc.driverClassName=com.mysql.jdbc.Driver 2 jdbc.url=jdbc\:mysql\://localhost\:3306/itheima09_hibernate 3 jdbc.username=root 4 jdbc.password=root
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:tx="http://www.springframework.org/schema/tx" 5 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 8 http://www.springframework.org/schema/aop 9 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 10 http://www.springframework.org/schema/tx 11 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 12 <!-- 13 引入dataSource 14 把dao層和service層的類導入進來 15 --> 16 <bean 17 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 18 <property name="locations"> 19 <value>classpath:jdbc.properties</value> 20 </property> 21 </bean> 22 <bean id="dataSource" destroy-method="close" 23 class="org.apache.commons.dbcp.BasicDataSource"> 24 <property name="driverClassName" value="${jdbc.driverClassName}" /> 25 <property name="url" value="${jdbc.url}" /> 26 <property name="username" value="${jdbc.username}" /> 27 <property name="password" value="${jdbc.password}" /> 28 </bean> 29 <bean id="studentDao" class="com.itheima09.spring.jdbc.transaction.dao.StudentDaoImpl"> 30 <property name="dataSource"> 31 <ref bean="dataSource"/> 32 </property> 33 </bean> 34 <bean id="studentService" class="com.itheima09.spring.jdbc.transaction.service.StudentServiceImpl"> 35 <property name="studentDao"> 36 <ref bean="studentDao"/> 37 </property> 38 </bean> 39 <!-- 40 事務管理器 41 告訴spring容器要採用什麼樣的技術處理事務 42 --> 43 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 44 <property name="dataSource"> 45 <ref bean="dataSource"/> 46 </property> 47 </bean> 48 <!-- 49 配置聲明的事務策略 50 id 惟一標示 51 transaction-manager 事務管理器 52 --> 53 <tx:advice id="tx" transaction-manager="transactionManager"> 54 <tx:attributes> 55 <!-- 56 以save開頭的方法,採用的傳播屬性是默認值,隔離機制是默認值,是讀寫事務 57 --> 58 <tx:method 59 name="save*" 60 propagation="REQUIRED" 61 isolation="DEFAULT" 62 read-only="false"/> 63 </tx:attributes> 64 </tx:advice> 65 <aop:config> 66 <aop:pointcut 67 expression="execution(* com.itheima09.spring.jdbc.transaction.service.*.*(..))" 68 id="perform"/> 69 <aop:advisor advice-ref="tx" pointcut-ref="perform"/> 70 </aop:config> 71 </beans>
1 package com.itheima09.spring.jdbc.transaction.dao; 2 3 public interface StudentDao { 4 public void saveStudent(String sql); 5 }
1 package com.itheima09.spring.jdbc.transaction.dao; 2 3 import org.springframework.jdbc.core.support.JdbcDaoSupport; 4 5 public class StudentDaoImpl extends JdbcDaoSupport implements StudentDao{ 6 public void saveStudent(String sql) { 7 this.getJdbcTemplate().execute(sql); 8 } 9 }
1 package com.itheima09.spring.jdbc.transaction.service; 2 3 public interface StudentService { 4 public void saveStudent(); 5 }
1 package com.itheima09.spring.jdbc.transaction.service; 2 3 import com.itheima09.spring.jdbc.transaction.dao.StudentDao; 4 5 public class StudentServiceImpl implements StudentService{ 6 private StudentDao studentDao; 7 8 public void setStudentDao(StudentDao studentDao) { 9 this.studentDao = studentDao; 10 } 11 public void saveStudent() { 12 this.studentDao.saveStudent("insert into student(name,description) values('1','1')"); 13 int a = 1/0; 14 this.studentDao.saveStudent("insert into student(name,description) values('1','1')"); 15 } 16 }
1 package com.itheima09.spring.jdbc.transaction.test; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 import com.itheima09.spring.jdbc.transaction.service.StudentService; 8 9 public class StudentServiceTest { 10 @Test 11 public void testStudent(){ 12 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 13 StudentService studentService = (StudentService)context.getBean("studentService"); 14 studentService.saveStudent(); 15 } 16 }
一、 業務邏輯類不能實現接口
二、 客戶端調用返回的是目標類(代理類的父類)
一、 若是一個DAO類繼承了HibernateDaoSupport,只須要在spring配置文件中注入SessionFactory就能夠了。
二、 若是一個DAO類沒有繼承HibernateDaoSupport,須要有一個SessionFactory的屬性,而且在配置文件中進行注入。
一、 在配置文件中引用spring的自動掃描機制。
二、 在配置文件中引入註解解析器
三、 在service層經過@Transaction進行註解
一、 hibernate的配置文件
二、 持久化類和映射文件
三、 Dao層和service層全部的類
四、 Spring的配置文件
五、 客戶端
從上圖能夠看出,程序員使用sessionFactory產生session,從而進行crud的操做
Spring容器利用sessionFactory產生session,進行事務的操做,因此spring容器產生
的session和程序員用的session確定是同一個session,因此在spring聲明式事務處理的
時候,session必須由當前線程產生。
案例:
1 <?xml version='1.0' encoding='utf-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <!-- 7 一個session-factory表明一個數據庫 8 --> 9 <session-factory> 10 <!-- 11 連接數據庫的用戶名 12 --> 13 <property name="connection.username">root</property> 14 <!-- 15 連接數據庫的密碼 16 --> 17 <property name="connection.password">root</property> 18 <!-- 19 連接數據庫的驅動 20 --> 21 <property name="connection.driver_class"> 22 com.mysql.jdbc.Driver 23 </property> 24 <!-- 25 連接數據庫的url 26 --> 27 <property name="connection.url"> 28 jdbc:mysql://localhost:3306/itheima09_hibernate 29 </property> 30 <!-- 31 方言 32 告訴hibernate用什麼樣的數據庫 33 --> 34 <property name="dialect"> 35 org.hibernate.dialect.MySQLDialect 36 </property> 37 <!-- 38 validate 加載hibernate時,驗證數據庫的結構 39 update 加載hibernate時,檢查數據庫,若是表不存在,則建立,若是存在,則更新 40 create 每次加載hiberante,都會建立表 41 create-drop 每次加載hiberante,建立,卸載hiberante時,銷燬 42 --> 43 <property name="hbm2ddl.auto">update</property> 44 <!-- 45 顯示sql語句 46 --> 47 <property name="show_sql">true</property> 48 <!-- 49 格式化sql語句 50 --> 51 <property name="format_sql">true</property> 52 <!-- 53 加載映射文件 54 --> 55 <mapping 56 resource="com/itheima09/spring/hibernate/transaction/domain/Person.hbm.xml" /> 57 </session-factory> 58 </hibernate-configuration>
1 jdbc.driverClassName=com.mysql.jdbc.Driver 2 jdbc.url=jdbc\:mysql\://localhost\:3306/itheima09_hibernate 3 jdbc.username=root 4 jdbc.password=root
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 11 <!-- 引入dataSource 把dao層和service層的類導入進來 --> 12 <bean 13 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 14 <property name="locations"> 15 <value>classpath:jdbc.properties</value> 16 </property> 17 </bean> 18 <bean id="dataSource" destroy-method="close" 19 class="org.apache.commons.dbcp.BasicDataSource"> 20 <property name="driverClassName" value="${jdbc.driverClassName}" /> 21 <property name="url" value="${jdbc.url}" /> 22 <property name="username" value="${jdbc.username}" /> 23 <property name="password" value="${jdbc.password}" /> 24 </bean> 25 26 <bean id="sessionFactory" 27 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 28 <property name="dataSource"> 29 <ref bean="dataSource" /> 30 </property> 31 <!-- 導入映射文件所在的路徑 --> 32 <property name="mappingDirectoryLocations"> 33 <list> 34 <value>classpath:com/itheima09/spring/hibernate/transaction/domain 35 </value> 36 </list> 37 </property> 38 <!-- 其餘配置 --> 39 <property name="hibernateProperties"> 40 <props> 41 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> 42 <prop key="hbm2ddl.auto">update</prop> 43 </props> 44 </property> 45 </bean> 46 <bean id="sessionFactory2" 47 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 48 <property name="configLocation"> 49 <value>classpath:hibernate.cfg.xml</value> 50 </property> 51 </bean> 52 <bean id="personDao" 53 class="com.itheima09.spring.hibernate.transaction.dao.PersonDaoImpl"> 54 <property name="sessionFactory"> 55 <ref bean="sessionFactory" /> 56 </property> 57 </bean> 58 <bean id="personService" 59 class="com.itheima09.spring.hibernate.transaction.service.PersonServiceImpl"> 60 <property name="personDao"> 61 <ref bean="personDao" /> 62 </property> 63 </bean> 64 <!-- 配置事務管理器 --> 65 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 66 <property name="sessionFactory"> 67 <ref bean="sessionFactory"/> 68 </property> 69 </bean> 70 <tx:advice id="tx" transaction-manager="transactionManager"> 71 <tx:attributes> 72 <tx:method name="save*" 73 isolation="DEFAULT" 74 propagation="REQUIRED" 75 read-only="false"/> 76 </tx:attributes> 77 </tx:advice> 78 <aop:config> 79 <aop:pointcut 80 expression="execution(* com.itheima09.spring.hibernate.transaction.service.*.*(..))" 81 id="perform" /> 82 <aop:advisor advice-ref="tx" pointcut-ref="perform" /> 83 </aop:config> 84 </beans>
1 package com.itheima09.spring.hibernate.transaction.dao; 2 3 import com.itheima09.spring.hibernate.transaction.domain.Person; 4 5 public interface PersonDao { 6 public void savePerson(Person person); 7 public void queryPerson(); 8 public void queryPersonCallback(); 9 }
1 <?xml version="1.0" encoding="utf-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- 6 描述一個持久化類 7 name屬性爲持久化類的全名 8 table 該持久化類對應的表名 默認狀況下爲類名 9 catalog 爲數據庫的名稱 10 --> 11 <class name="com.itheima09.spring.hibernate.transaction.domain.Person"> 12 <!-- 13 id對應表中的主鍵 14 name爲持久化類中屬性的名稱 15 length 爲對應數據庫表中相應字段的長度 16 column 屬性的名稱對應的表的字段名稱 不寫則默認和屬性的名稱一致 17 --> 18 <id name="pid" length="5" type="java.lang.Long" column="pid"> 19 <!-- 20 主鍵的生成器 21 --> 22 <generator class="increment"></generator> 23 </id> 24 <property name="name" column="name" type="java.lang.String" length="20"> 25 </property> 26 <property name="description" column="description" type="java.lang.String" length="50"> 27 </property> 28 </class> 29 </hibernate-mapping>
1 package com.itheima09.spring.hibernate.transaction.domain; 2 3 import java.io.Serializable; 4 5 import org.hibernate.impl.SessionFactoryImpl; 6 7 public class Person implements Serializable{ 8 private Long pid; 9 private String name; 10 private String description; 11 12 13 14 public Long getPid() { 15 return pid; 16 } 17 public void setPid(Long pid) { 18 this.pid = pid; 19 } 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 public String getDescription() { 27 return description; 28 } 29 public void setDescription(String description) { 30 this.description = description; 31 } 32 }
在dao裏常常有這樣的語句
1 public E findById(Serializable id) 2 { 3 return (E) getHibernateTemplate().get(clazz, id); 4 }
HibernateTemplate類源碼
1 public Object get(Class entityClass, Serializable id) throws DataAccessException { 2 return get(entityClass, id, null); 3 }
1 public Object get(final Class entityClass, final Serializable id, final LockMode lockMode) 2 throws DataAccessException { 3 return execute(new HibernateCallback() { 4 public Object doInHibernate(Session session) throws HibernateException { 5 if (lockMode != null) { 6 return session.get(entityClass, id, lockMode); 7 } 8 else { 9 return session.get(entityClass, id); 10 } 11 } 12 }, true); 13 }
1 public Object execute(HibernateCallback action) throws DataAccessException { 2 return execute(action, isExposeNativeSession()); 3 }
1 public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException { 2 Assert.notNull(action, "Callback object must not be null"); 3 Session session = getSession(); 4 boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory()); 5 if (existingTransaction) { 6 logger.debug("Found thread-bound Session for HibernateTemplate"); 7 } 8 FlushMode previousFlushMode = null; 9 try { 10 previousFlushMode = applyFlushMode(session, existingTransaction); 11 enableFilters(session); 12 Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session)); 13 Object result = action.doInHibernate(sessionToExpose); flushIfNecessary(session, existingTransaction); 14 return result; 15 } 16 catch (HibernateException ex) { 17 throw convertHibernateAccessException(ex); 18 } 19 catch (SQLException ex) { 20 throw convertJdbcAccessException(ex); 21 } 22 catch (RuntimeException ex) { 23 // Callback code threw application exception... 24 throw ex; 25 } 26 finally { 27 if (existingTransaction) { 28 logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate"); 29 disableFilters(session); 30 if (previousFlushMode != null) { 31 session.setFlushMode(previousFlushMode); 32 } 33 } 34 else { 35 // Never use deferred close for an explicitly new Session. 36 if (isAlwaysUseNewSession()) { 37 SessionFactoryUtils.closeSession(session); 38 } 39 else { 40 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory()); 41 } 42 } 43 } 44 }
HibernateTemplate類是對hibernate操做的封裝。若是要本身寫hibernate的操做,最麻煩的是那些要檢查的錯誤,並且每個地方都同樣。不同的地方只是真正對數據庫操做的語句。spring的想法是同樣的代碼抽取出來寫成一個HibernateTemplate中的execute方法。execute的方法參數是HibernateCallback接口類。HibernateCallback裏面定義了一個doInHibernate的方法。由於這個方法是變的。好比你是查找數據方法應該就是:session.load()。刪除數據就是session.delete().這樣的話查詢數據庫的方法用execute方法。
HibernateCallback 接口類
public interface HibernateCallback { Object doInHibernate(Session session) throws HibernateException, SQLException; }
而後使用內部類的形式把HibernateCallback中的方法doInHibernate實例化。
new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { if (lockMode != null) { return session.get(entityClass, id, lockMode); } else { return session.get(entityClass, id); } }
總的想法就是不變的東西能夠抽象出一個方法。好比對異常的檢查。變的東西,好比對數據庫的操做,抽象出一個接口的方法。
總結
JAVA的CALLBACK經過接口來實現。
例:
1.HibernateTemplate,內聯類
2.內聯類實現接口HibernateCallback的doInHibernate 方法
3.HibernateTemplate擁有一個參數爲HibernateCallback接口類型的函數execute(HibernateCallback action)方法.
4.調用HibernateTemplate的get方法時,將內聯類傳給了excute方法
5.執行excute方法時,(你調用它)
已取得內聯類,就能夠隨時回調它所實現的HibernateCallback接口中的方法了,
這時它反過來調用你的方法(它調用你),這就是回調了.
Javaeye兩個會員的理解,我以爲比較到位.
冉翔:
就是調用系統的一個方法,傳進去一個接口的實現類 or 匿名類。
而後系統的方法調用接口申明的方法,而且注入相應的參數
Buaawhl:
IoC, Functor, Visitor 都是 callback。
就是一個 Template Methond 裏面的flow不變,某一個步驟的具體操做變化,這個變化部須要 從外部(參數,或者屬性,或者 override parent method)注入。
相似於從前的 C 回調函數指針。
MainFlow ( callback ){
step1;
....
callback( someThing );
....
stepN;
}
注意配置文件裏applictionContext.xml
1 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 2 <property name="sessionFactory"><ref local="sessionFactory"/></property> 3 </bean> 4 <bean id="baseTransactionProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 5 <property name="transactionManager"> 6 <ref bean="transactionManager" /> 7 </property> 8 <property name="transactionAttributes"> 9 <props> 10 <prop key="save*">PROPAGATION_REQUIRED</prop> 11 <prop key="update*">PROPAGATION_REQUIRED</prop> 12 <prop key="find*">PROPAGATION_REQUIRED</prop> 13 <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 14 </props> 15 </property> 16 </bean>
1 package com.itheima09.spring.hibernate.callback; 2 3 import org.hibernate.Session; 4 5 public interface HibernateCallback { 6 public Object doInHibernate(Session session); 7 }
1 package com.itheima09.spring.hibernate.callback; 2 3 import java.util.List; 4 5 import org.hibernate.Session; 6 import org.hibernate.SessionFactory; 7 import org.hibernate.Transaction; 8 9 public class SpringHibernateCore { 10 private SessionFactory sessionFactory; 11 public void setSessionFactory(SessionFactory sessionFactory) { 12 this.sessionFactory = sessionFactory; 13 } 14 public Object doExecute(HibernateCallback action){ 15 Object obj = null; 16 Session session = sessionFactory.openSession(); 17 obj = action.doInHibernate(session); 18 session.close(); 19 return obj; 20 } 21 public List find(final String hql){ 22 return (List)this.doExecute(new HibernateCallback() { 23 public Object doInHibernate(Session session) { 24 return session.createQuery(hql).list(); 25 } 26 }); 27 } 28 } 29
1 package com.itheima09.spring.hibernate.callback; 2 3 import java.util.List; 4 5 import com.itheima09.spring.hibernate.transaction.domain.Person; 6 7 public class PersonDaoCallback extends SpringHibernateCore{ 8 public void queryPerson(){ 9 List<Person> pList = this.find("from Person"); 10 System.out.println(pList.size()); 11 } 12 }
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 11 <!-- 引入dataSource 把dao層和service層的類導入進來 --> 12 <bean 13 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 14 <property name="locations"> 15 <value>classpath:jdbc.properties</value> 16 </property> 17 </bean> 18 <bean id="dataSource" destroy-method="close" 19 class="org.apache.commons.dbcp.BasicDataSource"> 20 <property name="driverClassName" value="${jdbc.driverClassName}" /> 21 <property name="url" value="${jdbc.url}" /> 22 <property name="username" value="${jdbc.username}" /> 23 <property name="password" value="${jdbc.password}" /> 24 </bean> 25 26 <bean id="sessionFactory" 27 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 28 <property name="dataSource"> 29 <ref bean="dataSource" /> 30 </property> 31 <!-- 導入映射文件所在的路徑 --> 32 <property name="mappingDirectoryLocations"> 33 <list> 34 <value>classpath:com/itheima09/spring/hibernate/transaction/domain 35 </value> 36 </list> 37 </property> 38 <!-- 其餘配置 --> 39 <property name="hibernateProperties"> 40 <props> 41 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> 42 <prop key="hbm2ddl.auto">update</prop> 43 </props> 44 </property> 45 </bean> 46 <bean id="sessionFactory2" 47 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 48 <property name="configLocation"> 49 <value>classpath:hibernate.cfg.xml</value> 50 </property> 51 </bean> 52 53 <bean id="personDaoCallback" class="com.itheima09.spring.hibernate.callback.PersonDaoCallback"> 54 <property name="sessionFactory"> 55 <ref bean="sessionFactory2"/> 56 </property> 57 </bean> 58 </beans>
一、 在web.xml文件中,添加以下配置:
說明:
在web.xml中加載applicationContext.xml文件有幾種方式:
若是spring配置文件被命名爲applicationContext.xml,而且放在WEB-INF目錄下,則不須要配置<context-param>,由於ContextLoaderListener默認在WEB-INF目錄下尋找名爲applicationContext.xml的文件。若存在多個Spring配置文件,則在<param-value>中依次列出,之間以逗號隔開。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
利用classpath來配置
上面的配置說明在web容器啓動的時候,spring容器也啓動了。
在struts.xml文件中,添加struts2的常量:
struts.objectFactory = spring
在spring中的文件配置:
因爲使用的是spring的聲明式事務處理方式,因此在調用this.getHibernateTemplate().load方法時,使用了hibernate的懶加載技術。當把一個實體Bean從數據庫中加載完之後,只能加載其ID值。這個時候spring的聲明式事務處理方式已經把session給關閉掉了。因此當值在頁面輸出時會產生異常。
處理方式爲:OpenSessionInview模式。
誰能先測試先寫誰
數據庫的驅動包
Struts2的jar包
struts2-spring-plugin-2.3.1.2.jar struts2與spring整合的jar包
hibernate的jar 包
spring的jar包
Src
存放源代碼
Config
存放配置文件
Test
存放測試類
在該包下建立hibernate的配置文件
在applicationContext-db.xml文件中:
配置一個監聽器
配置一個過濾器
問題
一、 struts2的action爲何必須交給spring容器產生?
Action與service要作到徹底的鬆耦合,因此在action中的service必須由spring容器進行注入,那麼要完成該注入,action必須在spring容器中。因此action必須由spring容器產生。
二、 在整合的整個過程當中,spring容器用到了哪些知識點?
一、 爲了鬆耦合action與service,service與dao,使用了ioc和di
二、 爲了避免讓程序員接觸到事務,使用了聲明式的事務處理
三、 有可能會用springaop處理權限、日誌等內容
三、 在整合的過程當中,struts2用到了哪些知識點?
一、 mvc的做用
二、 使用插件的機制使得struts2與spring整合在一塊兒了,實際上就是把Struts2中的action交給spring處理了。
四、 在整合的過程當中,hibernate充當了什麼角色?數據庫的操做由hibernate充當
流程圖:
1 jdbc.driverClassName=com.mysql.jdbc.Driver 2 jdbc.url=jdbc\:mysql\://localhost\:3306/itheima09_hibernate 3 jdbc.username=root 4 jdbc.password=root
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 4 "http://struts.apache.org/dtds/struts-2.0.dtd"> 5 6 <struts> 7 <constant name="struts.devMode" value="true"/> 8 <include file="struts/struts-person.xml"></include> 9 </struts>
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 4 "http://struts.apache.org/dtds/struts-2.0.dtd"> 5 6 <struts> 7 <package name="person" namespace="/" extends="struts-default"> 8 <action name="personAction_*" method="{1}" class="personAction"> 9 <result name="index">index.jsp</result> 10 </action> 11 </package> 12 </struts>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 11 <import resource="applicationContext-db.xml"/> 12 <import resource="applicationContext-person.xml"/> 13 </beans>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 11 <bean id="sessionFactory" 12 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 13 <property name="configLocation"> 14 <value>classpath:hibernate/hibernate.cfg.xml</value> 15 </property> 16 </bean> 17 <!-- 18 事務管理器 19 --> 20 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 21 <property name="sessionFactory"> 22 <ref bean="sessionFactory"/> 23 </property> 24 </bean> 25 <tx:advice id="tx" transaction-manager="transactionManager"> 26 <tx:attributes> 27 <tx:method name="save*" 28 read-only="false"/> 29 </tx:attributes> 30 </tx:advice> 31 <aop:config> 32 <aop:pointcut 33 expression="execution(* com.itheima09.s2sh.service.impl.*.*(..))" 34 id="perform"/> 35 <aop:advisor advice-ref="tx" pointcut-ref="perform"/> 36 </aop:config> 37 </beans>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7 http://www.springframework.org/schema/aop 8 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 11 <bean id="personDao" class="com.itheima09.s2sh.dao.impl.PersonDaoImpl"> 12 <property name="sessionFactory"> 13 <ref bean="sessionFactory"/> 14 </property> 15 </bean> 16 <bean id="personService" class="com.itheima09.s2sh.service.impl.PersonServiceImpl"> 17 <property name="personDao"> 18 <ref bean="personDao"/> 19 </property> 20 </bean> 21 <bean id="personAction" 22 class="com.itheima09.s2sh.action.PersonAction" scope="prototype"> 23 <property name="personService"> 24 <ref bean="personService"/> 25 </property> 26 </bean> 27 </beans>
1 <?xml version='1.0' encoding='utf-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <!-- 7 一個session-factory表明一個數據庫 8 --> 9 <session-factory> 10 <!-- 11 連接數據庫的用戶名 12 --> 13 <property name="connection.username">root</property> 14 <!-- 15 連接數據庫的密碼 16 --> 17 <property name="connection.password">root</property> 18 <!-- 19 連接數據庫的驅動 20 --> 21 <property name="connection.driver_class"> 22 com.mysql.jdbc.Driver 23 </property> 24 <!-- 25 連接數據庫的url 26 --> 27 <property name="connection.url"> 28 jdbc:mysql://localhost:3306/itheima09_hibernate 29 </property> 30 <!-- 31 方言 32 告訴hibernate用什麼樣的數據庫 33 --> 34 <property name="dialect"> 35 org.hibernate.dialect.MySQLDialect 36 </property> 37 <!-- 38 validate 加載hibernate時,驗證數據庫的結構 39 update 加載hibernate時,檢查數據庫,若是表不存在,則建立,若是存在,則更新 40 create 每次加載hiberante,都會建立表 41 create-drop 每次加載hiberante,建立,卸載hiberante時,銷燬 42 --> 43 <property name="hbm2ddl.auto">update</property> 44 <!-- 45 顯示sql語句 46 --> 47 <property name="show_sql">true</property> 48 <!-- 49 格式化sql語句 50 --> 51 <property name="format_sql">true</property> 52 <!-- 53 加載映射文件 54 --> 55 <mapping resource="com/itheima09/s2sh/domain/Person.hbm.xml" /> 56 </session-factory> 57 </hibernate-configuration>
1 package com.itheima09.s2sh.action; 2 3 import com.itheima09.s2sh.domain.Person; 4 import com.itheima09.s2sh.service.PersonService; 5 import com.opensymphony.xwork2.ActionSupport; 6 7 public class PersonAction extends ActionSupport{ 8 private PersonService personService; 9 public void setPersonService(PersonService personService) { 10 this.personService = personService; 11 } 12 public String savePerson(){ 13 Person person = new Person(); 14 person.setName("asdf"); 15 this.personService.savePerson(person); 16 return "index"; 17 } 18 }
1 package com.itheima09.s2sh.dao; 2 3 import com.itheima09.s2sh.domain.Person; 4 5 public interface PersonDao { 6 public void savePerson(Person person); 7 }
1 package com.itheima09.s2sh.dao.impl; 2 3 import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 4 5 import com.itheima09.s2sh.dao.PersonDao; 6 import com.itheima09.s2sh.domain.Person; 7 8 public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao{ 9 public void savePerson(Person person) { 10 this.getHibernateTemplate().save(person); 11 } 12 }
1 package com.itheima09.s2sh.domain; 2 3 import java.io.Serializable; 4 5 import org.hibernate.impl.SessionFactoryImpl; 6 7 public class Person implements Serializable{ 8 private Long pid; 9 private String name; 10 private String description; 11 12 13 14 public Long getPid() { 15 return pid; 16 } 17 public void setPid(Long pid) { 18 this.pid = pid; 19 } 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 public String getDescription() { 27 return description; 28 } 29 public void setDescription(String description) { 30 this.description = description; 31 } 32 }
1 <?xml version="1.0" encoding="utf-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping> 5 <!-- 6 描述一個持久化類 7 name屬性爲持久化類的全名 8 table 該持久化類對應的表名 默認狀況下爲類名 9 catalog 爲數據庫的名稱 10 --> 11 <class name="com.itheima09.s2sh.domain.Person"> 12 <!-- 13 id對應表中的主鍵 14 name爲持久化類中屬性的名稱 15 length 爲對應數據庫表中相應字段的長度 16 column 屬性的名稱對應的表的字段名稱 不寫則默認和屬性的名稱一致 17 --> 18 <id name="pid" length="5" type="java.lang.Long" column="pid"> 19 <!-- 20 主鍵的生成器 21 --> 22 <generator class="increment"></generator> 23 </id> 24 <property name="name" column="name" type="java.lang.String" length="20"> 25 </property> 26 <property name="description" column="description" type="java.lang.String" length="50"> 27 </property> 28 </class> 29 </hibernate-mapping>
1 package com.itheima09.s2sh.service; 2 3 import com.itheima09.s2sh.domain.Person; 4 5 public interface PersonService { 6 public void savePerson(Person person); 7 }
1 package com.itheima09.s2sh.service.impl; 2 3 import com.itheima09.s2sh.dao.PersonDao; 4 import com.itheima09.s2sh.domain.Person; 5 import com.itheima09.s2sh.service.PersonService; 6 7 public class PersonServiceImpl implements PersonService{ 8 private PersonDao personDao; 9 public void setPersonDao(PersonDao personDao) { 10 this.personDao = personDao; 11 } 12 @Override 13 public void savePerson(Person person) { 14 this.personDao.savePerson(person); 15 } 16 }
1 package com.itheima09.s2sh.test; 2 3 import org.junit.Test; 4 5 import com.itheima09.s2sh.domain.Person; 6 import com.itheima09.s2sh.service.PersonService; 7 8 public class PersonTest extends SpringUtils{ 9 @Test 10 public void testSavePerson(){ 11 PersonService personService = (PersonService)context.getBean("personService"); 12 Person person = new Person(); 13 person.setName("aa"); 14 personService.savePerson(person); 15 } 16 }
1 package com.itheima09.s2sh.test; 2 3 import org.junit.Test; 4 5 public class SessionFactoryTest extends SpringUtils{ 6 @Test 7 public void testCreateTable(){ 8 9 } 10 }
1 package com.itheima09.s2sh.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class SpringUtils { 7 public static ApplicationContext context; 8 static{ 9 context = new ClassPathXmlApplicationContext("spring/applicationContext.xml"); 10 } 11 }