Spring AOP的环绕通知和前置、后置通知有着很大的区别,主要有两个重要的区别:
1)目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知是不能决定的,它们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。joinPoint.proceed()就是执行目标方法的代码。
2)环绕通知可以控制返回对象,即可以返回一个与目标对象完全不同的返回值。虽然这很危险,但是却可以做到。
下面的例子使用环绕通知,完成日志写入。
1)Spring配置文件加入AOP定义
<!--配置第三方平台请求日志切面-->
<bean id="logHandler" class="com.test.LogHandler" />
<aop:config>
<aop:aspect id="logAspect" ref="logHandler">
<aop:pointcut id="logPointCut" expression="execution(public * com.test.itf.*Ctr.*Hdl(..))"/>
<aop:around method="doAround" pointcut-ref="logPointCut"/>
</aop:aspect>
</aop:config>
public class LogHandler {
Logger logger = LoggerFactory.getLogger(LogHandler.class);
@Resource(name="logService")
private LogService logService;
public Object doAround(ProceedingJoinPoint joinPoint){
try{
Object ret = joinPoint.proceed(); //执行目标方法
Object[] args =joinPoint.getArgs(); //获取目标方法参数
String arg0 = joinPoint.getSignature().getDeclaringTypeName();
HttpServletRequest request =null ;
for(int i=0;i<args.length;i++){
if(args[i] instanceof HttpServletRequest ){
request = (HttpServletRequest) args[i]; //获取request参数对象
break;
}
}
JdResponse resp = (JdResponse) ret; //目标方法执行返回的对象
ConsumerLog log = new ConsumerLog();
log.setId(UuidUtil.get32UUID());
log.setCreateDate(new Date());
log.setAppId(request.getParameter("appId"));
log.setNonceStr(request.getParameter("nonceStr"));
log.setOutput(JSONObject.toJSONString(resp));
log.setInput(getHttpParameters(request));
logService.insertLog(log); //写入日志表
return resp;
}catch(Throwable e){
logger.error("error in logService doArround:",e);
return new JdResponse(JdResponse.CODE.serverError,"系统错误",null);
}
}
ProceedingJoinPoint对象表示连接点对象,该类是JoinPoint的子接口。该对象由spring自动传值,实现客户端给具体实现类的参数传递。