在Spring中,Advice都是通過Interceptor來實現的,主要有以下幾種:
1. 環繞Advice:
//例子摘自Spring reference public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; } public class DebugInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Before: invocation=[" + invocation + "]"); //(1) Object rval = invocation.proceed(); System.out.println("Invocation returned"); //(2) return rval; } }
環繞advice類似一個攔截器鏈,這個攔截器鏈的中心就是被攔截的方法。在程序(1)(2)我們可以加入我們自己的代碼,以表示在方法執行前后我們需要干什么。invocation.proceed()方法運行指向連接點的攔截器鏈並返回proceed()的結果。
2. Before Advice
public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method m, Object[] args, Object target) throws Throwable; }
一個更簡單的通知類型是before 通知。它不需要 MethodInvocation對象,因為它只是在進入方法之前被調用。before advice的一個主要優點是它不需要調用proceed()方法,因此就不會發生 無意間運行攔截器鏈失敗的情況。
3. After advice
public interface AfterReturningAdvice extends Advice { void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable; } !
一個After advice可以訪問返回值(但不能進行修改),被調用方法,方法參數以及目標對象。
4.Throws Advice
//ThrowsAdvice 是一個空接口,起標識作用 public interface ThrowsAdvice extends Advice { } //所給對象必須實現一個或者多個針對特定類型的異常通知方法,格式如下 afterThrowing([Method], [args], [target], subclassOfThrowable) //只有最后一個參數是必須的。因此異常通知方法對方法及參數的需求,方法的簽名將從一到四個參數之間變化。
最后還有一個是introduction advice,這個我想什么時候自己單獨做個例子理解一下。
做了個例子如下,想像一個用戶登錄場景:在登錄之前,我們對其輸入的用戶名進行有效性檢查;登錄成功后,我們記上用戶登錄次數;如果登錄失敗,則進行異常處理。實現代碼如下:
package com.learn.spring.test.advisor; //登錄的業務代碼 public interface LoginService { void login(String name, String password) throws UnauthorityException; } public class LoginServiceImpl implements LoginService { public void login(String name, String password) throws UnauthorityException { check(name, password); System.err.println(name + " is logining system..."); } private void check(String name, String password) throws UnauthorityException { if("myyate".equals(name) && "pass".equals(password) ) { System.err.println(name + " passed check...."); } else { throw new UnauthorityException("invalid password"); } } }
//用戶名檢查 攔截器 public class LoginNameCheckInterceptor implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { System.err.println("check user's name is valid?"); if(args[0] == null || "".equals(args[0].toString().trim())) { throw new IllegalArgumentException(); } } }
//用戶登錄次數統計攔截器 public class LoginCountInterceptor implements AfterReturningAdvice ...{ public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable ...{ System.err.println("Counting the login counts of " + args[0]); } }
//異常處理攔截器 public class ExceptionThrowInterceptor implements ThrowsAdvice { public void afterThrowing(Method m, Object[] args, Object target, IllegalArgumentException ex) throws Throwable { System.err.println("Login name is wrong, exception: " + ex); } public void afterThrowing(Method m, Object[] args, Object target, UnauthorityException ex) { System.err.println(target.getClass() + "." + m.getName() + "() throw a exception: " + ex.getMessage()); } }
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <bean id="loginServiceTarget" class="com.learn.spring.test.advisor.LoginServiceImpl"/> <bean id="loginNameCheckInterceptor" class="com.learn.spring.test.advisor.LoginNameCheckInterceptor"/> <!-- <bean id="loginCheckInterceptor" class="com.learn.spring.test.advisor.LoginCheckInterceptor"/> --> <bean id="loginCountInterceptor" class="com.learn.spring.test.advisor.LoginCountInterceptor"/> <bean id="exceptionThrowInterceptor" class="com.learn.spring.test.advisor.ExceptionThrowInterceptor"/> <bean id="loginService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"><ref local="loginServiceTarget"/></property> <property name="proxyInterfaces"> <list> <value>com.learn.spring.test.advisor.LoginService</value> </list> </property> <property name="interceptorNames"> <list> <value>loginNameCheckInterceptor</value> <value>loginCountInterceptor</value> <value>exceptionThrowInterceptor</value> </list> </property> </bean> </beans>
測試代碼運行:
public class Test { public static void main(String[] args) throws Exception { BeanFactory bf = BeanFactoryFactory.getBeanFactory("beans.xml", Test.class); LoginService ls = (LoginService) bf.getBean("loginService"); ls.login("myyate", "pass"); } }
輸出結果:
check user's name is valid?
myyate passed check....
myyate is logining system...
Counting the login counts of myyate
轉載:https://blog.csdn.net/caolaosanahnu/article/details/7914595