Spring的AOP框架允許你將分散在系統中的功能塊放到一個地方-切面。重用通用功能的常用面向對象技術是使用繼承和委
托模式。但由于基礎類在系統中到處使用,使用繼承會引起脆弱的繼承關系。委托模式比較笨拙,依然需要重復調用委托對象
。使用AOP,你也是在一個地方定義通用功能,只是你可以聲明式定義何時何地應用這些功能,而不一年歐冠在需要新功能的地
方修改代碼。交叉業務現在可以被模塊化到特定對象切面中。這樣做有2個好處,第一,現在每個業務邏輯放在一個地方,而不
是分散到代碼的各個角落。第二,我們的服務模塊現在更加清晰,因為他們只包含他們的核心功能,輔助功能轉移到切面中。
切面(Aspect):切面是你要實現的交叉功能。切面最常用的例子是日志記錄。日志記錄在系統中到處需要用到。
連接點(Joinpoint):連接點是應用程序執行過程中插入切面的地點。這個地點可以是方法調用,異常拋出,或者是要修改
字段。切面代碼在這些地方插入到你的應用流程中,添加新的行為。
通知(Advice):通知切面的實際實現。它通知應用系統新的行為。
切入點(PointCut):切入點定義了通知應該應用在哪些連接點。通知可以應用到AOP框架支持的任何連接點。你并不希望把
所有切面應用到所有可能的連接點上。切入點讓你指定通知應用到什么地方。
引入(Introduction):引入允許你為已存在類添加新方法和屬性。
目標對象(Target):目標對象是被通知對象。它既可以是你編寫的類也可以是你要添加定制行為的第三方類。
代理(Proxy):代理是將通知應用到目標對象后創建的對象。對于客戶對象來說,目標對象和代理對象是一樣的。
織入(Weaving):織入是將切面應用到目標對象從而創建一個新的代理對象的過程。
切入點定義了哪些連接點要被通知。
Spring的AOP實現:
在Spring中所有的通知都以Java類的形式編寫。代理Bean只有在第一次被應用系統需要的時候才被創建。如果你使用的是ApplicationContext,代理對象在BeanFactory載入所有Bean的時候被創建。因為Spring在運行期創建代理,所以使用Spring AOP不需要特殊編譯期。
Spring有2種代理創建方式。如果目標對象實現了一個接口暴露的方法,Spring將使用JDK的Java.lang.reflect.Proxy類創建代理。這個類讓Spring動態產生一個新的類,它實現了所需的接口,織入了通知,并且代理對目標對象的所有請求。
如果目標對象沒有實現任何接口,Spring使用CGLIB庫生成目標對象的子類。在創建這個子類的時候,Spring將通知織入,并且對目標對象的調用委托給這個子類。
通知包含了切面的邏輯。所以當你創建一個通知對象的時候,你是在編寫實現交叉功能的代碼。而且,記住Spring的連接點模型是建立在方法攔截上。這意味著你編寫的Spring通知會在方法調用周圍的各個地方織入系統中。通知的類型有:Around,Before,After,Throws
前置通知:需要擴展MethodBeforeAdvice接口
public interface MethodBeforeAdvice{
void before(Method method,Object[] args,Object target)throws Throwable;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 創建代理目標對象 -->
<bean id="kwikEMartTarget" class="com.springinaction.chapter03.store.ApuKwikEMart"></bean>
<!-- 創建通知 -->
<bean id="welcomeAdvice" class="com.springinaction.chapter03.store.WelcomeAdvice"></bean>
<!-- 創建代理對象 -->
<bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理類實現的接口 -->
<property name="proxyInterfaces">
<value>com.springinaction.chaper03.store.kwikEMart</value>
</property>
<!-- 要織入的通知 -->
<property name="interceptorNames">
<list>
<value>welcomeAdvice</value>
</list>
</property>
<!-- 要代理的目標對象 -->
<property name="target">
<ref bean="kwikEMartTarget"/>
</property>
</bean>
</beans>
ProxyFactoryBean類是一個在BeanFactory中顯示的創建代理對象的中心類。像我們展示的那樣,你可以給它一個要實現的接口,一個要代理的目標對象,一個要織入的通知,并且它將創建一個嶄新的代理對象。通常配置ProxyFactoryBean,讓它實現和目標對象一樣的接口。
后置通知:需要實現AfterReturningAdvice
public interface AfterReturningAdvice{
void afterReturning(Object returnValue,Method method,Object[] args,Object target)throws Throwable;
}
環繞通知:需要實現MethodInterceptor,同時實現前置和后置通知
public interface MethodInterceptor extends Interceptor{
Object invoke(MethodInvocation invocation)throws Throwable;
}
MethodInterceptor接口和前面介紹的2種通知不同點:
1、MethodInterceptor能夠控制目標方法是否真的被調用。通過調用MethodInvocation.proceed()方法來調用目標方法。這一點不同于前兩個,目標方法總是被調用的。
2、MethodInterceptor讓你可以控制返回的對象。就是說你可以返回一個與proceed()方法返回對象完全不同的對象。
package com.wyq.spring.base.aopinstance;
import java.util.HashSet;
import java.util.Set;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jboss.remoting.samples.transporter.basic.Customer;
/**
* @author 作者
* @version 創建時間:2009-11-5 下午05:19:19
* 類說明
*/
public class OnePerCustomerInterceptor implements MethodInterceptor {
//定義包含用戶的集合
private Set customers = new HashSet();
/*
* 當你在方法調用的前后都需要交叉切面邏輯時,應該使用MethodInterceptor。由于你必須要記得顯示調用
* invocation.proceed()方法,所以,在滿足要求的情況下,最好還是使用MethodBeforeAdvice或
* AfterReturningAdvice.
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Customer customer = (Customer)invocation.getArguments()[0];
if(customers.contains(customer)){
System.out.println("拋出異常");
}
//調用目標方法
Object squishee = invocation.proceed();
//添加用戶
customers.add(customer);
//返回目標方法結果
return squishee;
}
}
posted on 2009-11-05 17:31
王永慶 閱讀(227)
評論(0) 編輯 收藏 所屬分類:
SPRING