Spring中的Advice类型及其应用

本文详细介绍了Spring框架中的Advice类型,包括环绕Advice、BeforeAdvice、AfterAdvice和ThrowsAdvice等,并通过具体示例展示了如何在用户登录场景中运用这些Advice进行前置验证、后置处理及异常处理。
 

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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值