# 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
## 6.3? 基于Schema的AOP
基于Schema的AOP從Spring2.0之后通過“aop”命名空間來定義切面、切入點及聲明通知。
在Spring配置文件中,所以AOP相關定義必須放在<aop:config>標簽下,該標簽下可以有<aop:pointcut>、<aop:advisor>、<aop:aspect>標簽,配置順序不可變。
* <aop:pointcut>:用來定義切入點,該切入點可以重用;
* <aop:advisor>:用來定義只有一個通知和一個切入點的切面;
* <aop:aspect>:用來定義切面,該切面可以包含多個切入點和通知,而且標簽內部的通知和切入點定義是無序的;和advisor的區別就在此,advisor只包含一個通知和一個切入點。

6.3.1? 聲明切面
切面就是包含切入點和通知的對象,在Spring容器中將被定義為一個Bean,Schema方式的切面需要一個切面支持Bean,該支持Bean的字段和方法提供了切面的狀態和行為信息,并通過配置方式來指定切入點和通知實現。
切面使用<aop:aspect>標簽指定,ref屬性用來引用切面支持Bean。
切面支持Bean“aspectSupportBean”跟普通Bean完全一樣使用,切面使用“ref”屬性引用它。
### 6.3.2? 聲明切入點
切入點在Spring中也是一個Bean,Bean定義方式可以有很三種方式:
**1)在<aop:config>標簽下使用<aop:pointcut>聲明一個切入點Bean**,該切入點可以被多個切面使用,對于需要共享使用的切入點最好使用該方式,該切入點使用id屬性指定Bean名字,在通知定義時使用pointcut-ref屬性通過該id引用切入點,expression屬性指定切入點表達式:
1. <aop:config>??
2. <aop:pointcut?id="pointcut"?expression="execution(*?cn.javass..*.*(..))"/>??
3. <aop:aspect?ref="aspectSupportBean">??
4. <aop:before?pointcut-ref="pointcut"?method="before"/>??
5. </aop:aspect>??
6. </aop:config>??
**2)在<aop:aspect>標簽下使用<aop:pointcut>聲明一個切入點Bean**,該切入點可以被多個切面使用,但一般該切入點只被該切面使用,當然也可以被其他切面使用,但最好不要那樣使用,該切入點使用id屬性指定Bean名字,在通知定義時使用pointcut-ref屬性通過該id引用切入點,expression屬性指定切入點表達式:
1. <aop:config>??
2. <aop:aspect?ref="aspectSupportBean">??
3. <aop:pointcut?id="?pointcut"?expression="execution(*?cn.javass..*.*(..))"/>??
4. <aop:before?pointcut-ref="pointcut"?method="before"/>??
5. </aop:aspect>??
6. </aop:config>??
**3)匿名切入點Bean,**可以在聲明通知時通過pointcut屬性指定切入點表達式,該切入點是匿名切入點,只被該通知使用:
1. <aop:config>??
2. <aop:aspect?ref="aspectSupportBean">??
3. <aop:after?pointcut="execution(*?cn.javass..*.*(..))"?method="afterFinallyAdvice"/>??
4. </aop:aspect>??
5. </aop:config>??
### 6.3.3? 聲明通知
基于Schema方式支持前邊介紹的5中通知類型:
**一、前置通知:**在切入點選擇的方法之前執行,通過<aop:aspect>標簽下的<aop:before>標簽聲明:
1. <aop:before?pointcut="切入點表達式"??pointcut-ref="切入點Bean引用"??
2. method="前置通知實現方法名"??
3. arg-names="前置通知實現方法參數列表參數名字"/>??
**pointcut和pointcut-ref:**二者選一,指定切入點;
**method:**指定前置通知實現方法名,如果是多態需要加上參數類型,多個用“,”隔開,如beforeAdvice(java.lang.String);
**arg-names:**指定通知實現方法的參數名字,多個用“,”分隔,可選,類似于【3.1.2 構造器注入】中的參數名注入限制:**在class文件中沒生成變量調試信息是獲取不到方法參數名字的,因此只有在類沒生成變量調試信息時才需要使用arg-names屬性來指定參數名,如**arg-names="param"表示通知實現方法的參數列表的第一個參數名字為“param”。
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?void?sayBefore(String?param);??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?void?sayBefore(String?param)?{??
3. System.out.println("============say?"?+?param);??
4. }??
第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定義通知實現:
1. public?void?beforeAdvice(String?param)?{??
2. System.out.println("===========before?advice?param:"?+?param);??
3. }??
最后在chapter6/advice.xml配置文件中進行如下配置:
1. <bean?id="helloWorldService"?class="cn.javass.spring.chapter6.service.impl.HelloWorldService"/>??
2. <bean?id="aspect"?class="cn.javass.spring.chapter6.aop.HelloWorldAspect"/>??
3. <aop:config>??
4. <aop:aspect?ref="aspect">??
5. <aop:before?pointcut="execution(*?cn.javass..*.sayBefore(..))?and?args(param)"???
6. method="beforeAdvice(java.lang.String)"???
7. arg-names="param"/>??
8. </aop:aspect>??
9. </aop:config>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test??
2. public?void?testSchemaBeforeAdvice(){??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=?ctx.getBean("helloWorldService",?IHelloWorldService.class);??
6. helloworldService.sayBefore("before");??
7. System.out.println("======================================");??
8. }??
將輸入:
```
==========================================
===========before advice param:before
============say before
==========================================
```
分析一下吧:
**1)切入點匹配:**在配置中使用“execution(* cn.javass..*.sayBefore(..)) ”匹配目標方法sayBefore,且使用“args(param)”匹配目標方法只有一個參數且傳入的參數類型為通知實現方法中同名的參數類型;
**2)目標方法定義:**使用method=" beforeAdvice(java.lang.String) "指定前置通知實現方法,且該通知有一個參數類型為java.lang.String參數;
**3)目標方法參數命名:**其中使用arg-names=" param "指定通知實現方法參數名為“param”,切入點中使用“args(param)”匹配的目標方法參數將自動傳遞給通知實現方法同名參數。
**二、后置返回通知:**在切入點選擇的方法正常返回時執行,通過<aop:aspect>標簽下的<aop:after-returning>標簽聲明:
1. <aop:after-returning?pointcut="切入點表達式"??pointcut-ref="切入點Bean引用"??
2. method="后置返回通知實現方法名"??
3. arg-names="后置返回通知實現方法參數列表參數名字"??
4. returning="返回值對應的后置返回通知實現方法參數名"??
5. />??
**pointcut和pointcut-ref:**同前置通知同義;
**method:**同前置通知同義;
**arg-names:**同前置通知同義;
**returning:**定義一個名字,該名字用于匹配通知實現方法的一個參數名,當目標方法執行正常返回后,將把目標方法返回值傳給通知方法;returning限定了只有目標方法返回值匹配與通知方法相應參數類型時才能執行后置返回通知,否則不執行,對于returning對應的通知方法參數為Object類型將匹配任何目標返回值。
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?boolean?sayAfterReturning();??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?boolean?sayAfterReturning()?{??
3. System.out.println("============after?returning");??
4. return?true;??
5. }??
第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定義通知實現:
1. public?void?afterReturningAdvice(Object?retVal)?{??
2. System.out.println("===========after?returning?advice?retVal:"?+?retVal);??
3. }??
最后在chapter6/advice.xml配置文件中接著前置通知配置的例子添加如下配置:
1. <aop:after-returning?pointcut="execution(*?cn.javass..*.sayAfterReturning(..))"??
2. method="afterReturningAdvice"??
3. arg-names="retVal"????
4. returning="retVal"/>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test??
2. public?void?testSchemaAfterReturningAdvice()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=?ctx.getBean("helloWorldService",?IHelloWorldService.class);??
6. helloworldService.sayAfterReturning();??????
7. System.out.println("======================================");??
8. }??
將輸入:
```
======================================
============after returning
===========after returning advice retVal:true
======================================
```
分析一下吧:
**1)切入點匹配:**在配置中使用“execution(* cn.javass..*.sayAfterReturning(..)) ”匹配目標方法sayAfterReturning,該方法返回true;
**2)目標方法定義:**使用method="afterReturningAdvice"指定后置返回通知實現方法;
**3)目標方法參數命名:**其中使用arg-names="retVal"指定通知實現方法參數名為“retVal”;
**4)返回值命名:**returning="retVal"用于將目標返回值賦值給通知實現方法參數名為“retVal”的參數上。
**三、后置異常通知:**在切入點選擇的方法拋出異常時執行,通過<aop:aspect>標簽下的<aop:after-throwing>標簽聲明:
1. <aop:after-throwing?pointcut="切入點表達式"??pointcut-ref="切入點Bean引用"??
2. method="后置異常通知實現方法名"??
3. arg-names="后置異常通知實現方法參數列表參數名字"??
4. throwing="將拋出的異常賦值給的通知實現方法參數名"/>??
**pointcut和pointcut-ref:**同前置通知同義;
**method:**同前置通知同義;
**arg-names:**同前置通知同義;
**throwing:**定義一個名字,該名字用于匹配通知實現方法的一個參數名,當目標方法拋出異常返回后,將把目標方法拋出的異常傳給通知方法;throwing限定了只有目標方法拋出的異常匹配與通知方法相應參數異常類型時才能執行后置異常通知,否則不執行,對于throwing對應的通知方法參數為Throwable類型將匹配任何異常。
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?void?sayAfterThrowing();??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?void?sayAfterThrowing()?{??
3. System.out.println("============before?throwing");??
4. throw?new?RuntimeException();??
5. }??
第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定義通知實現:
1. public?void?afterThrowingAdvice(Exception?exception)?{??
2. System.out.println("===========after?throwing?advice?exception:"?+?exception);??
3. }??
最后在chapter6/advice.xml配置文件中接著前置通知配置的例子添加如下配置:
1. <aop:after-throwing?pointcut="execution(*?cn.javass..*.sayAfterThrowing(..))"??
2. method="afterThrowingAdvice"??
3. arg-names="exception"??
4. throwing="exception"/>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test(expected?=?RuntimeException.class)??
2. public?void?testSchemaAfterThrowingAdvice()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=?ctx.getBean("helloWorldService",?IHelloWorldService.class);??
6. helloworldService.sayAfterThrowing();??
7. System.out.println("======================================");??
8. }??
將輸入:
```
======================================
============before throwing
===========after throwing advice exception:java.lang.RuntimeException
======================================
```
分析一下吧:
**1)切入點匹配:**在配置中使用“execution(* cn.javass..*.sayAfterThrowing(..))”匹配目標方法sayAfterThrowing,該方法將拋出RuntimeException異常;
**2)目標方法定義:**使用method="afterThrowingAdvice"指定后置異常通知實現方法;
**3)目標方法參數命名:**其中使用arg-names="exception"指定通知實現方法參數名為“exception”;
**4)異常命名:**returning="exception"用于將目標方法拋出的異常賦值給通知實現方法參數名為“exception”的參數上。
**四、后置最終通知:**在切入點選擇的方法返回時執行,不管是正常返回還是拋出異常都執行,通過<aop:aspect>標簽下的<aop:after >標簽聲明:
1. <aop:after?pointcut="切入點表達式"??pointcut-ref="切入點Bean引用"??
2. method="后置最終通知實現方法名"??
3. arg-names="后置最終通知實現方法參數列表參數名字"/>??
**pointcut和pointcut-ref:**同前置通知同義;
**method:**同前置通知同義;
**arg-names:**同前置通知同義;
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?boolean?sayAfterFinally();??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?boolean?sayAfterFinally()?{??
3. System.out.println("============before?finally");??
4. throw?new?RuntimeException();??
5. }??
第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定義通知實現:
1. public?void?afterFinallyAdvice()?{??
2. System.out.println("===========after?finally?advice");??
3. }??
最后在chapter6/advice.xml配置文件中接著前置通知配置的例子添加如下配置:
1. <aop:after?pointcut="execution(*?cn.javass..*.sayAfterFinally(..))"??
2. method="afterFinallyAdvice"/>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test(expected?=?RuntimeException.class)??
2. public?void?testSchemaAfterFinallyAdvice()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=?ctx.getBean("helloWorldService",?IHelloWorldService.class);??
6. helloworldService.sayAfterFinally();??
7. System.out.println("======================================");??
8. }??
將輸入:
```
======================================
============before finally
===========after finally advice
======================================
```
分析一下吧:
**1)切入點匹配:**在配置中使用“execution(* cn.javass..*.sayAfterFinally(..))”匹配目標方法sayAfterFinally,該方法將拋出RuntimeException異常;
**2)目標方法定義:**使用method=" afterFinallyAdvice "指定后置最終通知實現方法。
**五、環繞通知:**環繞著在切入點選擇的連接點處的方法所執行的通知,環繞通知非常強大,可以決定目標方法是否執行,什么時候執行,執行時是否需要替換方法參數,執行完畢是否需要替換返回值,可通過<aop:aspect>標簽下的<aop:around >標簽聲明:
1. <aop:around?pointcut="切入點表達式"??pointcut-ref="切入點Bean引用"??
2. method="后置最終通知實現方法名"??
3. arg-names="后置最終通知實現方法參數列表參數名字"/>??
**pointcut和pointcut-ref:**同前置通知同義;
**method:**同前置通知同義;
**arg-names:**同前置通知同義;
環繞通知第一個參數必須是org.aspectj.lang.ProceedingJoinPoint類型,在通知實現方法內部使用ProceedingJoinPoint的proceed()方法使目標方法執行,proceed 方法可以傳入可選的Object[]數組,該數組的值將被作為目標方法執行時的參數。
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?void?sayAround(String?param);??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?void?sayAround(String?param)?{??
3. System.out.println("============around?param:"?+?param);??
4. }??
第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定義通知實現:
1. public?Object?aroundAdvice(ProceedingJoinPoint?pjp)?throws?Throwable?{??
2. System.out.println("===========around?before?advice");??
3. Object?retVal?=?pjp.proceed(new?Object[]?{"replace"});??
4. System.out.println("===========around?after?advice");??
5. return?retVal;??
6. }??
最后在chapter6/advice.xml配置文件中接著前置通知配置的例子添加如下配置:
1. <aop:around?pointcut="execution(*?cn.javass..*.sayAround(..))"??
2. method="aroundAdvice"/>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test??
2. public?void?testSchemaAroundAdvice()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=??
6. ctx.getBean("helloWorldService",?IHelloWorldService.class);??
7. helloworldService.sayAround("haha");??
8. System.out.println("======================================");??
9. }??
將輸入:
```
======================================
===========around before advice
============around param:replace
===========around after advice
======================================
```
分析一下吧:
**1)切入點匹配:**在配置中使用“execution(* cn.javass..*.sayAround(..))”匹配目標方法sayAround;
**2)目標方法定義:**使用method="aroundAdvice"指定環繞通知實現方法,在該實現中,第一個方法參數為pjp,類型為ProceedingJoinPoint,其中“Object retVal = pjp.proceed(new Object[] {"replace"});”,用于執行目標方法,且目標方法參數被“new Object[] {"replace"}”替換,最后返回“retVal ”返回值。
**3)測試:**我們使用“helloworldService.sayAround("haha");”傳入參數為“haha”,但最終輸出為“replace”,說明參數被替換了。
### 6.3.4? 引入
Spring引入允許為目標對象引入新的接口,通過在< aop:aspect>標簽內使用< aop:declare-parents>標簽進行引入,定義方式如下:
1. <aop:declare-parents??
2. types-matching="AspectJ語法類型表達式"??
3. implement-interface=引入的接口"???????????????
4. default-impl="引入接口的默認實現"??
5. delegate-ref="引入接口的默認實現Bean引用"/>??
**types-matching:**匹配需要引入接口的目標對象的AspectJ語法類型表達式;
**implement-interface:**定義需要引入的接口;
**default-impl和delegate-ref:**定義引入接口的默認實現,二者選一,default-impl是接口的默認實現類全限定名,而delegate-ref是默認的實現的委托Bean名;
接下來讓我們練習一下吧:
首先定義引入的接口及默認實現:
1. package?cn.javass.spring.chapter6.service;??
2. public?interface?IIntroductionService?{??
3. public?void?induct();??
4. }??
1. package?cn.javass.spring.chapter6.service.impl;??
2. import?cn.javass.spring.chapter6.service.IIntroductionService;??
3. public?class?IntroductiondService?implements?IIntroductionService?{??
4. @Override??
5. public?void?induct()?{??
6. System.out.println("=========introduction");??
7. }??
8. }??
其次在chapter6/advice.xml配置文件中接著前置通知配置的例子添加如下配置:
1. <aop:declare-parents??
2. types-matching="cn.javass..*.IHelloWorldService+"??
3. implement-interface="cn.javass.spring.chapter6.service.IIntroductionService"???????????????????????????
4. default-impl="cn.javass.spring.chapter6.service.impl.IntroductiondService"/>??
最后測試一下吧,測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test??
2. public?void?testSchemaIntroduction()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IIntroductionService?introductionService?=??
6. ctx.getBean("helloWorldService",?IIntroductionService.class);??
7. introductionService.induct();??
8. System.out.println("======================================");??
9. }??
將輸入:
```
======================================
=========introduction
======================================
```
分析一下吧:
**1)目標對象類型匹配:**使用types-matching="cn.javass..*.IHelloWorldService+"匹配IHelloWorldService接口的子類型,如HelloWorldService實現;
**2)引入接口定義:**通過implement-interface屬性表示引入的接口,如“cn.javass.spring.chapter6.service.IIntroductionService”。
**3)引入接口的實現:**通過default-impl屬性指定,如“cn.javass.spring.chapter6.service.impl.IntroductiondService”,也可以使用“delegate-ref”來指定實現的Bean。
**4)獲取引入接口:**如使用“ctx.getBean("helloWorldService", IIntroductionService.class);”可直接獲取到引入的接口。
### 6.3.5 Advisor
Advisor表示只有一個通知和一個切入點的切面,由于Spring AOP都是基于AOP聯盟的攔截器模型的環繞通知的,所以引入Advisor來支持各種通知類型(如前置通知等5種),Advisor概念來自于Spring1.2對AOP的支持,在AspectJ中沒有相應的概念對應。
Advisor可以使用<aop:config>標簽下的<aop:advisor>標簽定義:
1. <aop:advisor?pointcut="切入點表達式"?pointcut-ref="切入點Bean引用"??
2. advice-ref="通知API實現引用"/>??
**pointcut和pointcut-ref:**二者選一,指定切入點表達式;
**advice-ref:**引用通知API實現Bean,如前置通知接口為MethodBeforeAdvice;
接下來讓我們看一下示例吧:
首先在cn.javass.spring.chapter6.service.IhelloWorldService定義一個測試方法:
1. public?void?sayAdvisorBefore(String?param);??
其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定義實現
1. @Override??
2. public?void?sayAdvisorBefore(String?param)?{??
3. System.out.println("============say?"?+?param);??
4. }??
第三定義前置通知API實現:
1. package?cn.javass.spring.chapter6.aop;??
2. import?java.lang.reflect.Method;??
3. import?org.springframework.aop.MethodBeforeAdvice;??
4. public?class?BeforeAdviceImpl?implements?MethodBeforeAdvice?{??
5. @Override??
6. public?void?before(Method?method,?Object[]?args,?Object?target)?throws?Throwable?{??
7. System.out.println("===========before?advice");??
8. }??
9. }??
在chapter6/advice.xml配置文件中先添加通知實現Bean定義:
2. <bean?id="beforeAdvice"?class="cn.javass.spring.chapter6.aop.BeforeAdviceImpl"/>??
然后在<aop:config>標簽下,添加Advisor定義,添加時注意順序:
1. <aop:advisor?pointcut="execution(*?cn.javass..*.sayAdvisorBefore(..))"??
2. advice-ref="beforeAdvice"/>??
測試代碼cn.javass.spring.chapter6.AopTest:
1. @Test??
2. public?void?testSchemaAdvisor()?{??
3. System.out.println("======================================");??
4. ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("chapter6/advice.xml");??
5. IHelloWorldService?helloworldService?=??
6. ctx.getBean("helloWorldService",?IHelloWorldService.class);??
7. helloworldService.sayAdvisorBefore("haha");??
8. System.out.println("======================================");??
9. }???
將輸入:
```
======================================
===========before advice
============say haha
======================================
```
在此我們只介紹了前置通知API,其他類型的在后邊章節介紹。
不推薦使用Advisor,除了在進行事務控制的情況下,其他情況一般不推薦使用該方式,該方式屬于侵入式設計,必須實現通知API。
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC