簡述spring中常有的幾種advice?


在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM