spring心得8--AOP各種通知案例講解.doc
上一篇部落格中已經簡單介紹了,這裡通過案例詳細說明一下aop中各種通知的用法。
先列出後面介紹的JDK動態代理通知(主要區別於cglib代理而言,下面會具體介紹)、靜態切入點、正則切入點等都依賴使用的抽象主題(一個介面,可以是多個)、是、真實主題(改介面的實現類)
介面:SayService.java
package www.csdn.spring.proxy.advice;
public interface SayService {
public void say(String content);
public void sayHi();
public void sayHello();
public void byebye();
}
實現類:SayServiceImpl.java
package www.csdn.spring.proxy.advice;
public interface SayService {
public void say(String content);
public void sayHi();
public void sayHello();
public void byebye();
}
實現類:SayServiceImpl.java
package www.csdn.spring.proxy.advice;
public class SayServiceImpl implements SayService{
@Override
public void say(String content) {
System.out.println("say:"+content);
//int i=1/0;
}
@Override
public void sayHi() {
System.out.println("===sayHi()方法執行了===");
}
@Override
public void sayHello() {
System.out.println("===sayHello()方法執行了===");
}
@Override
public void byebye() {
System.out.println("===byebye()方法執行了===");
}
}
1.各種通知的使用,JDK動態代理
前置通知、後置通知、環繞通知、異常通知、引入通知的案例分析,下面註釋都有詳細解釋,這裡不再贅述。
spring-advice.xml spring配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 建立前置通知 -->
<bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
<!-- 建立後置通知 -->
<bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
<!-- 建立環繞通知 -->
<bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
<!-- 建立異常通知 -->
<bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
<!-- 引入通知 -->
<bean id="auditableAdvice" class="www.csdn.spring.proxy.advice.AuditableImpl"/>
<!-- 真實主題 目標物件 -->
<bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
<!-- 配置代理操作 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--抽象主題 實現介面 -->
<property name="proxyInterfaces">
<array>
<value>www.csdn.spring.proxy.advice.SayService</value>
<value>www.csdn.spring.proxy.advice.Auditable</value>
</array>
</property>
<!-- 目標物件 -->
<property name="target">
<ref bean="sayServiceImpl"/>
</property>
<!-- 織入的通知的名稱 -->
<property name="interceptorNames">
<array>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>aroundAdvice</value>
<value>throwAdvice</value>
<value>auditableAdvice</value>
</array>
</property>
</bean>
</beans>
下面是這幾個通知具體反映到的類,最關鍵的是這個幾個通知代理類所要繼承的介面,不可寫錯,更不可不寫,否則會出錯,這些錯誤將在後期本人一篇spring錯誤總結的部落格中涉及到,敬請期待。
前者通知類:BeforeAdvice.java
package www.csdn.spring.proxy.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("在目標方法執行之前執行........................");
// 執行完之後執行exit方法,退出程式
//System.exit(0);
// 暴露的引數的含義
System.out.println("目標方法:" + method.getName());
if (args != null && args.length > 0) {
for (Object arg : args) {
System.out.println("傳遞的引數值:" + arg);
}
}
System.out.println("目標物件:" + target.getClass());
}
}
後置通知類:AfterAdvice.java
package www.csdn.spring.proxy.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AfterAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("在目標方法執行之後執行..............................");
}
}
環繞通知類:AroundAdvice.java
package www.csdn.spring.proxy.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {
public void beforeMethod() {
System.out.println("around---------------------目標方法之前執行");
}
public void afterMethod() {
System.out.println("around---------------------目標方法之後執行");
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object returnValue = null;
beforeMethod();
returnValue = invocation.proceed();
afterMethod();
return returnValue;
}
}
異常通知類:ThrowsAdvice.java
package www.csdn.spring.proxy.advice;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
public class ThrowAdvice implements ThrowsAdvice{
public void afterThrowing(Method m,Object[] os,Object
target,Throwable throwable){
System.out.println("出現異常了:"+throwable.getLocalizedMessage());
}
}
引用通知需要注意是,因為這裡spring使用的是jdk動態代理,所以使用引用通知的時候一定先建立一個引用通知的抽象介面,再建立一個引用通知類。
抽象主題 Auditable.java
package www.csdn.spring.proxy.advice;
import java.util.Date;
public interface Auditable {
public void setDate(Date date);
public Date getDate();
}
引用通知類 AuditableService.java
package www.csdn.spring.proxy.advice;
import java.util.Date;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class AuditableImpl extends DelegatingIntroductionInterceptor implements Auditable {
private Date date;
@Override
public void setDate(Date date) {
this.date = date;
}
@Override
public Date getDate() {
return date;
}
}
測試類 AdviceTest.java
package www.csdn.spring.proxy.advice;
import java.util.Date;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdviceTest {
@Test
public void testAdvice() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:spring-advice.xml");
// 不使用代理的時候
// context.getBean("sayServiceImpl",SayServiceImpl.class).say("嗨!楊凱!");
// 使用代理的時候
SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
sayService.say("嗨!楊凱!");
//引入通知測試
Auditable auditable = (Auditable) sayService;
auditable.setDate(new Date());
System.out.println(auditable.getDate());
}
}
2.各種通知的使用,cglib代理
spring中的JDK動態代理和cglib代理區別就是:1)在配置檔案中的區別,即在配置檔案中抽象主鍵,介面物件配置不同,具體不同詳見下面紅色部分;主要通過property屬性的proxyTargetClass值設定。2)即JDK動態代理和cglib代理的不同,前者基於介面代理,後者基於類代理,所以這裡就有了真實主題的不同,即實現類的不同,cglib的真實主題沒有實現任何介面。
spring-advices.xml spring配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 建立前置通知 -->
<bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
<!-- 建立後置通知 -->
<bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
<!-- 建立環繞通知 -->
<bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
<!-- 建立異常通知 -->
<bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
<!-- 真實主題 目標物件 -->
<bean id="sayServiceImpls" class="www.csdn.spring.proxy.advice.SayServiceImpls"/>
<!-- 配置代理操作 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--抽象主題 實現介面 -->
<!-- 寫法一:直接使用代理類,不再去指明是哪個代理類 ;這個時候value的值不管是true或false都其作用-->
<property name="proxyTargetClass" value="true"/>
<!-- 指明代理類,這時候value必須是true的時候才起作用 ;
使用false會報錯:Bean named 'proxyFactoryBean' must be of type [www.csdn.spring.advice.SayServiceImpls],
but was actually of type [$Proxy4]
<property name="proxyInterfaces">
<array>
<value>www.csdn.spring.proxy.advice.SayService</value>
</array>
</property>
<property name="proxyTargetClass">
<value>true</value>
</property>
-->
<!-- 目標物件 -->
<property name="target">
<ref bean="sayServiceImpls"/>
</property>
<!-- 織入的通知的名稱 -->
<property name="interceptorNames">
<array>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>aroundAdvice</value>
<value>throwAdvice</value>
</array>
</property>
</bean>
</beans>
真實主題:SayServiceImpls.java
package www.csdn.spring.proxy.advice;
public class SayServiceImpls{
public void say(String content) {
System.out.println("say:"+content);
}
}
測試類 AdviceTests.java
package www.csdn.spring.proxy.advice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdviceTests {
@Test
public void testAdvice() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:spring-advices.xml");
// 不使用代理的時候
// context.getBean("sayServiceImpls",SayServiceImpls.class).say("嗨!你好!");
// 使用代理的時候
context.getBean("proxyFactoryBean", SayServiceImpls.class).say("嗨!你好!");
}
}
3.靜態切入點
為什麼會有靜態切入點,上一篇看部落格已經介紹過,為了使你編寫的通知,即代理在指定切入點起作用,也就是所謂的是aop的通知有實用價值。這裡通過案例詳細分析靜態切入點。
spring-staticAdvisor.xml spring配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 建立前置通知 -->
<bean id="beforeAdvice" class="www.csdn.spring.proxy.advice.BeforeAdvice"/>
<!-- 建立後置通知 -->
<bean id="afterAdvice" class="www.csdn.spring.proxy.advice.AfterAdvice"/>
<!-- 建立環繞通知 -->
<bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
<!-- 建立異常通知 -->
<bean id="throwAdvice" class="www.csdn.spring.proxy.advice.ThrowAdvice"/>
<!-- 靜態切入點 -->
<bean id="nameMatchMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 織入通知,比如環繞通知 -->
<property name="advice">
<ref bean="aroundAdvice"/>
</property>
<!-- 指明切入點 -->
<property name="mappedName">
<value>say</value>
</property>
</bean>
<!-- 真實主題 目標物件 -->
<bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
<!-- 配置代理操作 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--抽象主題 實現介面 -->
<property name="proxyInterfaces">
<array>
<value>www.csdn.spring.proxy.advice.SayService</value>
</array>
</property>
<!-- 目標物件 -->
<property name="target">
<ref bean="sayServiceImpl"/>
</property>
<!-- 織入的通知的名稱 -->
<property name="interceptorNames">
<array>
<value>nameMatchMethodPointcutAdvisor</value>
</array>
</property>
</bean>
</beans>
測試類 AdvisorTest.java
package www.csdn.spring.proxy.advice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdvisorTest {
@Test
public void testAdvice() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:spring-s*.xml");
// 使用代理的時候
SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
sayService.say("嗨!楊凱,你好!");
sayService.sayHi();
sayService.sayHello();
sayService.byebye();
}
}
4.正則切入點
閒話少說,與靜態切入點不同的就是正則切入點匹配正規表示式,重點程式碼見下面紅色部分.
spring-regAdvisor.xml spring配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 建立環繞通知 -->
<bean id="aroundAdvice" class="www.csdn.spring.proxy.advice.AroundAdvice"/>
<!-- 靜態切入點 -->
<bean id="regexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- 織入通知,比如環繞通知 -->
<property name="advice">
<ref bean="aroundAdvice"/>
</property>
<!-- 指明切入點 -->
<property name="patterns">
<!-- .是萬用字元的意思;第一個.*代表匹配任何包名和類名 ;第二個.*代表匹配以say開頭的任意方法-->
<array>
<value>.*sayH.</value>
<value>.*bye.*</value>
<value>www.*\.SayService\.sayHell.</value>
</array>
</property>
</bean>
<!-- 真實主題 目標物件 -->
<bean id="sayServiceImpl" class="www.csdn.spring.proxy.advice.SayServiceImpl"/>
<!-- 配置代理操作 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--抽象主題 實現介面 -->
<property name="proxyInterfaces">
<array>
<value>www.csdn.spring.proxy.advice.SayService</value>
</array>
</property>
<!-- 目標物件 -->
<property name="target">
<ref bean="sayServiceImpl"/>
</property>
<!-- 織入的通知的名稱 -->
<property name="interceptorNames">
<array>
<value>regexpMethodPointcutAdvisor</value>
</array>
</property>
</bean>
</beans>
測試類 AdvisorTest.java
package www.csdn.spring.proxy.advice;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdvisorTest {
@Test
public void testAdvice() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:spring-r*.xml");
// 使用代理的時候
SayService sayService = context.getBean("proxyFactoryBean", SayService.class);
sayService.say("嗨!楊凱,你好!");
sayService.sayHi();
sayService.sayHello();
sayService.byebye();
}
}
相關文章
- oracle心得2--單行函式理論講解與案例分析.docOracle函式
- spring心得9--自動代理知識點講解及案例分析Spring
- spring心得6--自動裝配知識點講解及案例分析Spring
- 運維注意事項及案例講解(個人心得)運維
- Spring 各種註解備註Spring
- 面試可能會遇到的各種問題講解面試
- spring心得3--bean的生命週期結合案例詳細講解@普通期圖解與uml圖解一併分析SpringBean圖解
- 老鳥向新手講解各種程式設計比賽程式設計
- spring心得7--spring第二大特點AOP(面向切面)講解Spring
- java反射案例講解Java反射
- Java Spring各種依賴注入註解的區別JavaSpring依賴注入
- DRM 分析及案例講解
- Spring AOP中的前置通知和後置通知詳解Spring
- Java獲取Spring的各種物件JavaSpring物件
- spring和Mybatis的各種查詢SpringMyBatis
- spring心得4--setter注入集合(set、list、map、properties等多種集合,配有案例解析)@基本裝Spring
- jQuery心得5--jQuery深入瞭解串講1jQuery
- sql優化講課中引出的各種問題!SQL優化
- Oracle ADF 應用--案例講解Oracle
- Spring Boot整合 Geodesy講解Spring Boot
- Java的演算法講解以及案例!Java演算法
- Spring進階案例之註解和IoC案例Spring
- 圖解 SQL 裡的各種 JOIN圖解SQL
- Android 的各種 Drawable 詳解Android
- JavaScript 各種遍歷方式詳解JavaScript
- Spring入門(七):Spring Profile使用講解Spring
- oracle心得3--多表查詢@分組查詢@子查詢講解與案例分析@經典練習題Oracle
- Spring原始碼心得Spring原始碼
- Spring-Aop註解形式案例Spring
- MVC 三層架構案例詳細講解MVC架構
- 常用的資料分析方法及案例講解
- spring心得1--spring入門介紹@bean的載入初講@第一個spring專案helloWordSpringBean
- Oracle經典sql語句總結@sql-plus重點函式串講與sql語句案例@中文排序詳講).docOracleSQL函式排序
- Spring:Bean的scope作用域案例講解以及Bean之間的依賴和繼承(3)SpringBean繼承
- SAP各種BOM詳解(包含常用BAPI)API
- 強力解決npm各種大姨媽NPM
- windows的各種副檔名詳解Windows
- spring心得10--使用Aspectj進行AOP開發介紹及案例分析Spring