Spring AOP 提供的四个Advice
spring面向切面编程,主要就是基于动态代理。单独抽象出非业务的功能,服务于某些业务方法。
Spring提供了四种很实用的Advice,
分别为:Before Advice, After Returning Advice, Around Advice, After throwing Advice。
都是方法级别的,就是在某个方法执行前后插入一些非业务的操作,如打日志或者判断权限等。
对于这四种advice的实现,spring都提供了三种方法,分别为基于接口、基于xml和基于annotation(注释)。
Before Advice会在目标对象的方法执行之前被调用;
After Advice会在目标方法执行之后被调用;
Around Advice则可以在目标方法执行前后同时加上相关服务;
Throw Advice是在异常发生后执行某些操作。
BeforeAdvice 需要实现 org.springframework.aop.MethodBeforeAdvice 接口:
After Advice实现org.springframework.aop.AfterReturningAdvice 接口:
Around Advice需要实现org.aopalliance.intercept.MethodInterceptor 接口:
类前面的注释说明了该方法的使用,就是要在invoke()方法中调用MethodInvocation.proceed(),将执行传给下一个Interceptor,
最终执行目标方法。在proceed()方法前后加操作,到达Aroud advice的作用。
说明:
使用 BeanNameAutoProxyCreator 实现spring的自动代理
提到代理,我们可以使用ProxyBeanFactory,并配置proxyInterfaces,target和interceptorNames实现,
但如果需要代理的bean很多,无疑会对spring配置文件的编写带来繁重的工作.
Spring为我们提供了,根据beanName匹配后进行自动代理的解决方法.
(Spring拦截器,Spring方法拦截)
拦截器(也称拦截机)拦截机 (Interceptor), 是 AOP (Aspect-Oriented Programming) 的另一种叫法。
spring面向切面编程,主要就是基于动态代理。单独抽象出非业务的功能,服务于某些业务方法。
Spring提供了四种很实用的Advice,
分别为:Before Advice, After Returning Advice, Around Advice, After throwing Advice。
都是方法级别的,就是在某个方法执行前后插入一些非业务的操作,如打日志或者判断权限等。
对于这四种advice的实现,spring都提供了三种方法,分别为基于接口、基于xml和基于annotation(注释)。
Before Advice会在目标对象的方法执行之前被调用;
After Advice会在目标方法执行之后被调用;
Around Advice则可以在目标方法执行前后同时加上相关服务;
Throw Advice是在异常发生后执行某些操作。
1.基于接口的Advice
这个就需要自定义的 Aspect 实现Spring接口。BeforeAdvice 需要实现 org.springframework.aop.MethodBeforeAdvice 接口:
/**
* Advice invoked before a method is invoked. Such advices cannot
* prevent the method call proceeding, unless they throw a Throwable.
*
* @see AfterReturningAdvice
* @see ThrowsAdvice
*
* @author Rod Johnson
*/
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* Callback before a given method is invoked.
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
After Advice实现org.springframework.aop.AfterReturningAdvice 接口:
/**
* After returning advice is invoked only on normal method return, not if an
* exception is thrown. Such advice can see the return value, but cannot change it.
*
* @author Rod Johnson
* @see MethodBeforeAdvice
* @see ThrowsAdvice
*/
public interface AfterReturningAdvice extends AfterAdvice {
/**
* Callback after a given method successfully returned.
* @param returnValue the value returned by the method, if any
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
Around Advice需要实现org.aopalliance.intercept.MethodInterceptor 接口:
package org.aopalliance.intercept;
/**
* Intercepts calls on an interface on its way to the target. These
* are nested "on top" of the target.
*
* <p>The user should implement the {@link #invoke(MethodInvocation)}
* method to modify the original behavior. E.g. the following class
* implements a tracing interceptor (traces all the calls on the
* intercepted method(s)):
*
* <pre class=code>
* class TracingInterceptor implements MethodInterceptor {
* Object invoke(MethodInvocation i) throws Throwable {
* System.out.println("method "+i.getMethod()+" is called on "+
* i.getThis()+" with args "+i.getArguments());
* Object ret=i.proceed();
* System.out.println("method "+i.getMethod()+" returns "+ret);
* return ret;
* }
* }
* </pre> */
public interface MethodInterceptor extends Interceptor {
/**
* Implement this method to perform extra treatments before and
* after the invocation. Polite implementations would certainly
* like to invoke {@link Joinpoint#proceed()}.
*
* @param invocation the method invocation joinpoint
* @return the result of the call to {@link
* Joinpoint#proceed()}, might be intercepted by the
* interceptor.
*
* @throws Throwable if the interceptors or the
* target-object throws an exception. */
Object invoke(MethodInvocation invocation) throws Throwable;
}
类前面的注释说明了该方法的使用,就是要在invoke()方法中调用MethodInvocation.proceed(),将执行传给下一个Interceptor,
最终执行目标方法。在proceed()方法前后加操作,到达Aroud advice的作用。
2,以下是使用 MethodInterceptor 接口实现的一个列子:
说明:
使用 BeanNameAutoProxyCreator 实现spring的自动代理
提到代理,我们可以使用ProxyBeanFactory,并配置proxyInterfaces,target和interceptorNames实现,
但如果需要代理的bean很多,无疑会对spring配置文件的编写带来繁重的工作.
Spring为我们提供了,根据beanName匹配后进行自动代理的解决方法.
(Spring拦截器,Spring方法拦截)
拦截器(也称拦截机)拦截机 (Interceptor), 是 AOP (Aspect-Oriented Programming) 的另一种叫法。
2.1,spring的配置如下:
<!-- spring方法拦截器类-->
<bean id="springMethodInterceptor" class="com.system.service.SpringMethodInterceptor">
<!-- <property name="param">
<value>${param}</value>
</property> -->
</bean>
<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Service*</value>
<value>*Dao*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>springMethodInterceptor</value>
</list>
</property>
</bean>
2.2,SpringMethodInterceptor类如下:
package com.system.service;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.struts2.ServletActionContext;
/**
* @author Weijun Hu
*
*/
public class SpringMethodInterceptor implements MethodInterceptor {
/**
private String param;
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
*/
public Object invoke(MethodInvocation mi) throws Throwable {
String interfaceName = mi.getMethod().getDeclaringClass().getName();
String className = mi.getThis().getClass().getName();
String methodName = mi.getMethod().getName();
System.out.println("调用的类为:" + className);
System.out.println("调用的方法为:" + methodName);
//以下几行是获取方法上的annotation
//MethodMark methodMark = mi.getMethod().getAnnotation(MethodMark.class);
//if(methodMark==null || !methodMark.isLog()){
// return mi.proceed();
//}
//Object[] args = mi.getArguments();
Object obj = null;
String errorInfo = "";
boolean pass = false;
try{
obj = mi.proceed();
pass = true;
}catch(Exception e){
e.printStackTrace();
errorInfo = e.getMessage();
throw e;
}finally{
if(obj!=null){
//TODO
}
//根据pass判断是否执行成功
}
return obj;
}
}