在Spring中,相關的api提供了對某類方法的攔截,也提供了對某些類的代理,以下是本人對spring參考手冊的了解,純屬一家之言。對方法的攔截通過定義配置Advisior,Advice,Pointcut而實作;通過Advised接口實作代理類的生成,以下分兩方面攔截者和代理類來闡述
I、攔截者
一、Spring中的Advisor,Advice,Point概述
1、Advisor:充當Advice和Pointcut的擴充卡,類似使用Aspect的@Aspect注解的類(前一章節所述)。一般有advice和pointcut屬性。
祖先接口為org.springframework.aop.Advisor,應用中可直接使用org.springframework.aop.support.DefaultPointcutAdvisor
2、Advice:用于定義攔截行為,祖先接口為org.aopalliance.aop.Advice,該接口隻是辨別接口,應用中可直接實作BeforeAdvice ,ThrowsAdvice,MethodInterceptor ,AfterReturningAdvice ,IntroductionInterceptor 等子接口
3、Pointcut:用于定義攔截目标集合,祖先接口為org.springframework.aop.Pointcut
二、Spring中的Advisor,Advice,Point的應用
1、編寫Advisor實作類
在此可直接使用org.springframework.aop.support.DefaultPointcutAdvisor
2、編寫Advice實作類
public class PlayAdvice implements MethodBeforeAdvice{
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("my before advice");
// method.invoke(target, args); 如果再調用這句,則目标方法會執行多一次
}
}
3、編寫Pointcut實作類
public class PlayPointcut implements Pointcut {
public ClassFilter getClassFilter() {
return new PlayClassFilter();
}
public MethodMatcher getMethodMatcher() {
return new PlayMethodMatcher();
}
}
//PlayClassFilter的定義
class PlayClassFilter implements ClassFilter {
public boolean matches(Class clazz) {
if(clazz.getSimpleName().equals("Play"))
return true;
return false;
}
}
//PlayMethodMatcher的定義
class PlayMethodMatcher implements MethodMatcher {
public boolean isRuntime() {
return true;
}
public boolean matches(Method method, Class c) {
if(c.getSimpleName().equals("Play")&&method.getName().contains("Service"))
return true;
return false;
}
public boolean matches(Method method, Class c, Object[] args) {
if(c.getSimpleName().equals("Play")&&method.getName().contains("Service"))
return true;
return false;
}
}
4、編寫目标類
public class Play {
public void playService(String what){
System.out.println("play "+what);
}
}
5、在配置檔案中配置
<bean id="adviceBean" class="com.hss.sp.aop.PlayAdvice"/>
<bean id="pointcutBean" class="com.hss.sp.aop.PlayPointcut"/>
<bean id="playService" class="com.hss.sp.service.Play"/>
<bean
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="adviceBean"></property>
<property name="pointcut" ref="pointcutBean"></property>
</bean>
6、測試,結果
BeanFactory bf=new ClassPathXmlApplicationContext("applicationContext.xml");
Play play=(Play)bf.getBean("playService");
play.playService("pingpong");
輸出:
my before advice
play pingpong
II、代理者
在Spring中建立了AOP代理之後,你能夠使用
org.springframework.aop.framework.Advised
接口對它們進行管理。 任何AOP代理都能夠被轉型為這個接口,不論它實作了哪些其它接口。這個接口包括下面的方法:
Advisor[] getAdvisors();
void addAdvice(Advice advice) throws AopConfigException;
void addAdvice(int pos, Advice advice)
throws AopConfigException;
void addAdvisor(Advisor advisor) throws AopConfigException;
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
int indexOf(Advisor advisor);
boolean removeAdvisor(Advisor advisor) throws AopConfigException;
void removeAdvisor(int index) throws AopConfigException;
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
boolean isFrozen();
getAdvisors()
方法将為每個已經被加入工廠的通知器,攔截器或者其它通知類型傳回一個通知器。如果你曾經添加一個通知器,那麼所傳回的通知器将是你加入的對象。 如果你曾經加入一個攔截器或者其它通知類型,Spring将把它們包裝在一個通知器裡,後者使用一個永遠傳回true的切入點。是以如果你曾經加入一個
MethodInterceptor
, 傳回的通知器将是一個
DefaultPointcutAdvisor
,它可以傳回你加入的
MethodInterceptor
和一個比對所有類和方法的切入點。
addAdvisor()
方法可以用來添加任何通知器。通常儲存切入點和通知的通知器是
DefaultPointcutAdvisor
,它可以用于任何通知或切入點(但不包括引入類型)。
預設情況下,你可以加入或移除通知器或者攔截器甚至當代理已經被建立之後。唯一的限制是無法加入或者移除一個引入通知器,因為工廠中獲得的已有代理不能顯示接口的改變(你可以通過從工廠裡擷取一個新的代理來避免這個問題)。
下面是一個簡單的例子,它把一個AOP代理轉型為
Advised
接口,檢查并操作它的通知:
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(new DebugInterceptor());
// Add selective advice using a pointcut
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors",
oldAdvisorCount + 2, advised.getAdvisors().length);