在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