前言:在之前的文章中我介绍了Spring面向切面编程(AOP)以及如何定义自定义注解的相关内容。在JavaSE中,如果想要使用自定义注解还是比较麻烦的,需要自己手动定义该注解的注解解析器。相反,如果想要在基于Spring的框架中使用自定义注解的话,结合AOP切面编程将可以很容易地处理自定义的注解
注:如果对AOP切面或者自定义注解的一些基本用法不太熟悉的话可以参考我之前写过的这两篇文章:
- Java基础系列20:自定义注解以及通过自定义注解解析器解析注解:www.zifangsky.cn/803.html
- Spring面向切面编程(AOP)的基本用法:基于注解的实现:www.zifangsky.cn/788.html
下面我将以通过一个简单的实例来详细说明相关实现。该例子的逻辑很简单,就是定义一个日志记录相关的注解,然后通过AOP拦截标注了该注解的方法进行日志记录。详细配置如下:
(1)自定义日志记录相关注解:
package cn.zifangsky.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SaveLog {
//是否保存请求参数
boolean saveRequests() default false;
//备注
String note() default "";
}
上面的代码很简单,就是定义了一个可以在方法上可以使用的用于记录日志的注解
(2)定义一个切面拦截处理标注了该注解的方法:
package cn.zifangsky.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SaveLogAspect {
private final Logger logger = Logger.getLogger(SaveLogAspect.class);
//切点
@Pointcut("execution(* cn.zifangsky..*.*(..)) && @annotation(log)")
public void mark(SaveLog log){}
/**
* 环绕通知
* @param pJoinPoint
* @param log @SaveLog注解
* @return
* @throws Throwable
*/
@Around("mark(log)")
public Object saveLog(ProceedingJoinPoint pJoinPoint,SaveLog log) throws Throwable{
Object result = null;
// Class cla = null;
StringBuffer stringBuffer = new StringBuffer();
//方法执行前记录
try {
//通过反射获取拦截的方法
// cla = pJoinPoint.getTarget().getClass();
//方法签名
String signature = pJoinPoint.getSignature().toString();
//方法名
// String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
stringBuffer.append("***********" + signature.toString() + "***********");
stringBuffer.append(System.getProperty("line.separator"));
//记录方法请求参数
if(log.saveRequests()){
Object[] parames = pJoinPoint.getArgs(); //目标方法参数
String paramStr = parseParames(parames);
stringBuffer.append("*******Parames:" + paramStr);
stringBuffer.append(System.getProperty("line.separator"));
}
//记录备注
stringBuffer.append("*******Note:" + log.note());
stringBuffer.append(System.getProperty("line.separator"));
} catch (Exception e) {
stringBuffer.append(e.getStackTrace());
stringBuffer.append(System.getProperty("line.separator"));
}finally {
result = pJoinPoint.proceed();
}
//方法执行后记录
stringBuffer.append("***********end***********");
stringBuffer.append(System.getProperty("line.separator"));
logger.debug(stringBuffer.toString());
return result;
}
/**
* 请求参数格式转换
* @param parames
* @return
*/
private String parseParames(Object[] parames){
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("[");
if(parames != null && parames.length > 0){
for(Object object : parames){
stringBuffer.append(object.toString() + ",");
}
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
}
stringBuffer.append("]");
return stringBuffer.toString();
}
}
上面的代码都是AOP的一些基本用法,定义了一个环绕通知,然后根据@SaveLog 注解的参数情况进行日志记录。代码逻辑很简单,并且关键点已经添加了注释,因此这里就不多做分析了
(3)修改Spring和SpringMVC的配置文件:
ii)在SpringMVC的配置文件中添加:
这里之所以在SpringMVC的配置文件中也添加AOP代理,其目的是为了上面定义的切面能够正常拦截Controller中的方法
(4)在Controller中使用自定义注解:
package cn.zifangsky.controller;
import javax.servlet.ServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.zifangsky.aop.SaveLog;
@Controller
public class AOPTestController {
@RequestMapping("/testaop.html")
@SaveLog(note="测试Controller调用",saveRequests = true)
public void test(ServletRequest request){
System.out.println("-----------method executing-------------");
}
}
(5)测试:
启动项目后,访问:http://localhost:9180/Demo/testaop.html
然后查看日志文件,可以发现已经生成了这样的记录:
2016-12-04 18:29:01,589 DEBUG [cn.zifangsky.aop.SaveLogAspect] - ***********void cn.zifangsky.controller.AOPTestController.test(ServletRequest)***********
*******Parames:[cn.zifangsky.filter.XSSFilter$EscapeScriptwrapper@3633e32e]
*******Note:测试Controller调用
***********end***********
这就证明了在上面定义的AOP切面中已经正确得到标注了@SaveLog注解的方法的详细内容了,同时日志文件也按照我们的预期进行了记录。至此,关于“Spring中使用AOP切面解析处理自定义注解”就全部结束了