当前位置: 代码迷 >> Web前端 >> Spring中的Advice部类及其应用
  详细解决方案

Spring中的Advice部类及其应用

热度:484   发布时间:2013-03-01 18:33:02.0
Spring中的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
  相关解决方案