需求:定义一个注解,被该注解标注的方法,会输出系统日志。
1.定义注解
package com.zyf.springMVC.customannotation;
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.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLogger {
/**
* 日志主题
*/
String value() default "";
}
2.注解AOP
package com.zyf.springMVC.customannotation;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/** 注解@SysLogger的AOP */
@Aspect
@Component
public class SysLoggerAspect {
private Logger logger;
/** 日志主题 */
private String logTheme;
/** 切点 */
@Pointcut(value = "@annotation(SysLogger)")
public void pointCut() {
}
/** 环绕通知 */
@Around("pointCut()")
public void around(ProceedingJoinPoint pj) {
Long start = System.currentTimeMillis();
getLogger(pj).info(getLogTheme(pj) + "...开始。");
try {
// 显式回调目标对象的原有方法
pj.proceed();
} catch (Throwable e) {
getLogger(pj).info(getLogTheme(pj) + "...异常:" + e.getMessage());
e.printStackTrace();
}
getLogger(pj).info(getLogTheme(pj) + "...结束。");
getLogger(pj).info(getLogTheme(pj) + "...耗时=" + (System.currentTimeMillis() - start) + "毫秒");
}
/** 获取日志记录对象 */
private Logger getLogger(JoinPoint point) {
if (null != logger) {
return logger;
}
Logger logger = LoggerFactory.getLogger(point.getTarget().getClass());
return logger;
}
/** 获取日志主题 */
private String getLogTheme(JoinPoint point) {
if (!StringUtils.isEmpty(logTheme)) {
return logTheme;
}
MethodSignature methodSignature = (MethodSignature) point.getSignature();
Method method = methodSignature.getMethod();
SysLogger annotation = method.getAnnotation(SysLogger.class);
String value = annotation.value();
return value;
}
}
3.被标注的方法
package com.zyf.springMVC.customannotation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/customannotation")
public class CustomAnnotationController {
@RequestMapping("/ca1")
@SysLogger(value="自定义注解测试")
public ModelAndView ca1(@RequestParam int id) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("customannotation/ca1");
modelAndView.addObject("username", "张三");
modelAndView.addObject("id", id);
if(0==id){
throw new RuntimeException("用户id不能为0");
}
return modelAndView;
}
}
测试:
url:http://localhost:8080/customannotation/ca1?id=1
输出日志:
2019-11-04 11:10:01.535 INFO 6772 --- [nio-8080-exec-1] c.z.s.c.CustomAnnotationController : 自定义注解测试...开始。
2019-11-04 11:10:01.543 INFO 6772 --- [nio-8080-exec-1] c.z.s.c.CustomAnnotationController : 自定义注解测试...结束。
2019-11-04 11:10:01.543 INFO 6772 --- [nio-8080-exec-1] c.z.s.c.CustomAnnotationController : 自定义注解测试...耗时=12毫秒
github:https://github.com/zhangyangfei/SpringBootLearn.git中的springMVC工程。