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自動傳值,實現客戶端給具體實現類的參數傳遞。