您的位置:首页 > 编程语言 > Java开发

使用Spring AOP和自定义注解记录日志

2018-04-02 20:02 671 查看
什么是注解?      对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
  Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
什么是AOP?    它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
我今天要做的就是利用以上这两样东西,实现在每个有某自定义注解的方法被调用时,都去打印操作日志。
自定义注解:自定义注解类编写的一些规则:
  1. Annotation型定义为@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.
  2. 参数成员只能用public或默认(default)这两个访问权修饰
  3. 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.
  4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象,因为你除此之外没有别的获取注解对象的方法
  5. 注解也可以没有定义成员, 不过这样注解就没啥用了
PS:自定义注解需要使用到元注解元注解:作用:负责注解其他注解(可用于自定义注解)1、@Retention作用:标示注解在什么时候可见(运行时可见、仅在.class文件及源代码中可见、仅在源代码中可见),value可用参数有:
属性值作用
RetentionPolicy.RUNTIME
标示该注解可以再运行时通过反射找到(ORM框架许多注解使用了该参数)
RetentionPolicy.CLASS
标示该注解保存在.class文件中,但在运行时不能通过反射找到
RetentionPolicy.SOURSE
标示该注解只在源码中可见
2、@Target作用:标示该注解用于注解什么元素(类、方法、变量等),value可用参数有:
属性值作用
ElementType.PACKAGE
标示该注解用于注解包声明
ElementType.ANNOTATION_TYPE
标示该注解用于注解其他注解
ElementType.CONSTRUCTOR
标示该注解用于注解构造函数
ElementType.FIELD
标示该注解用于注解成员变量
ElementType.METHOD
标示该注解用于注解方法
ElementType.TYPE
标示该注解用于注解类,接口,枚举类型
ElementType.PARAMETER
标示该注解用于注解参数
ElementType.LOCAL_VARIABLE
标示该注解用于注解局部变量
3、@Inherited作用:指定被它修饰的注解具有继承性(比如InheritedAnnotation注解了BaseClass,SubClass继承了BaseClass,这时SubClass也会具有InheritedAnnotation注解,但方法跟参数等的注解不会被继承)4、@Documented作用:表明被注解元素应该加入到JavaDoc(文档)下面步入正题,开始编码1、注解定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
/** 操作类型(INSERT、UPDATE、SELECT、DELETE)*/
public String optType();
/** 描述 */
public String describe();
/** 模块 */
public String module();
}
2、定义一个切面,并定义方法返回时和方法报错时的处理逻辑:@Aspect
@Component(value = "loggerAspect")
public class LoggerAspect {

private Logger logger = LoggerFactory.getLogger(LoggerAspect.class);

@Pointcut("execution(public * com.wb.wbao.web.*.*(..)) && @annotation(com.wb.wbao.common.annotation.Loggable)")
public void log(){
}

@AfterReturning(value = "log()", returning = "retVal")
public void log(JoinPoint joinPoint, Object retVal) {
// 获取参数
Object[] params = joinPoint.getArgs();
// 获取方法名
String methodName = joinPoint.getSignature().getName();
Class<?> targetClass = joinPoint.getTarget().getClass();
Method method = null;
for (Method mt : targetClass.getMethods()) {
if (methodName.equals(mt.getName())) {
method = mt;
break;
}
}
Loggable loggable = method.getAnnotation(Loggable.class);
if(Objects.isNull(loggable)){
return;
}
logger.info("loggable desc:{}, optType:{}, module:{},params:{}", loggable.describe(), loggable.optType(), loggable.module(), params);
//loggable desc:登录, optType:POST, module:LOGIN,params:[User{loginName='wangbao', password='wangbao'}
}

@AfterThrowing(value = "log()", throwing = "ex")
public void log(JoinPoint joinPoint, Throwable ex) {
// 获取参数
Object[] params = joinPoint.getArgs();
// 获取方法名
String methodName = joinPoint.getSignature().getName();
Class<?> targetClass = joinPoint.getTarget().getClass();
Method method = null;
for (Method mt : targetClass.getMethods()) {
if (methodName.equals(mt.getName())) {
method = mt;
break;
}
}
Loggable loggable = method.getAnnotation(Loggable.class);
if(Objects.isNull(loggable)){
return;
}

logger.info("loggable desc:{}, optType:{}, module:{}, exception:{}, params:{}", loggable.describe(), loggable.optType(), loggable.module(), ex.getMessage(), params);
//loggable desc:登录, optType:POST, module:LOGIN, exception:/ by zero, params:[User{loginName='wangbao', password='wangbao'}
}
}3、实际使用该注解:
@Loggable(describe = "登录", optType = "POST", module = "LOGIN")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public CommonDTO login(@RequestBody User user) {...}启动项目,登录系统,如果登录成功则看到日志:

如果登录失败(被调用的方法抛出异常),则看到日志:


9b69
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: