温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用java注解和aspectj AOP怎么实现打印日志

发布时间:2021-02-20 13:53:46 来源:亿速云 阅读:309 作者:Leah 栏目:开发技术

本篇文章给大家分享的是有关使用java注解和aspectj AOP怎么实现打印日志,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

1.首先需要自定义注解:

systemName:表示该系统的名称。

bizCode:表示具体的方法描述

logtype:表示日志的格式类型

package myspring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LogAnnotation {
 String systemName();
 String bizCode();
 LogType logtype() default LogType.TIME;
}

2.定义日志格式枚举:

package myspring;
public enum LogType {
 TIME("TIME", "方法调用时间"),
 PARAM("PARAM", "参数打印");
 private String type;
 private String desc;
 LogType(String type, String desc) {
  this.type = type;
  this.desc = desc;
 }
 public String getType() {
  return type;
 }
 public void setType(String type) {
  this.type = type;
 }
 public String getDesc() {
  return desc;
 }
 public void setDesc(String desc) {
  this.desc = desc;
 }
}

3.切面代码:

其中execution(* *(..))

第一个* :表示所有返回值

第二个* :表示所有包匹配规则和所有类匹配规则以及所有方法匹配规则

两个点.. :表示任何参数匹配

例如:

execution(* *..*Service.*(..))

表示任何返回值 任何包以Service结尾的类或者实现类的任何方法任何参数

*.. :表示所有包

* :Service表示所有以Service结尾的类或者实现类

execution(* cn.lijie.MyService.*(..))

表示任何返回值 cn.lijie包下面 MyService类或者实现类的所有方法 所有参数

代码如下:

package myspring;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
@Component
@Aspect
public class LogAspect {
 private static Logger thisLog = LoggerFactory.getLogger(LogAspect.class);
 private static Logger timeLog = LoggerFactory.getLogger(TimeTypeLog.class);
 private static Logger paramLog = LoggerFactory.getLogger(ParamTypeLog.class);
 @Around("execution(* *(..)) && @annotation(logAnnotation)")
 public Object log(ProceedingJoinPoint point, LogAnnotation logAnnotation) {
  StopWatch stop = new StopWatch();
  stop.start();
  boolean flag = false;
  Object retValue = null;
  try {
   retValue = point.proceed();
   flag = true;
  } catch (Throwable throwable) {
   throwable.printStackTrace();
  } finally {
   stop.stop();
   if (logAnnotation.logtype().equals(LogType.TIME)) {
    timeLog(this.getMethod(point), point, stop.getTotalTimeMillis(), logAnnotation, flag);
   } else {
    paramLog(this.getMethod(point), point, retValue);
   }
  }
  return retValue;
 }
 private void timeLog(String method, ProceedingJoinPoint point, long totalTimeMillis, LogAnnotation logAnnotation, boolean flag) {
  timeLog.info("系统为:{},调用的方法名字:{},调用是否成功:{},运行时间为:{}ms", logAnnotation.systemName(), method, flag, totalTimeMillis);
 }
 private void paramLog(String method, ProceedingJoinPoint point, Object retValue) {
  try {
   String result = JSON.toJSONString(retValue);
   //获取入参
   Object[] args = point.getArgs();
   StringBuffer sb = new StringBuffer();
   for (Object obj : args) {
    String str = JSON.toJSONString(obj);
    sb.append(subStr(str, 200)).append(" ");
   }
   paramLog.info("调用方法为:{},入参为:{},出参为:{}", method, sb, subStr(result, 200));
  } catch (Exception e) {
   thisLog.warn("切面日志 参数日志打印异常,异常信息:{}", e.getMessage());
  }
 }
 private String getMethod(ProceedingJoinPoint pjp) {
  MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
  return methodSignature.getDeclaringTypeName() + "#" + methodSignature.getMethod().getName();
 }
 private String subStr(String string, int length) {
  if (!StringUtils.isEmpty(string)) {
   if (string.length() > length) {
    string = string.substring(0, 200);
    return string;
   }
  }
  return string;
 }
}

4.定义一个操作对象:

package myspring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component("logTest")
public class LogTest {
 private static Logger logger = LoggerFactory.getLogger(LogTest.class);
 @LogAnnotation(systemName = "计算器系统", bizCode = "+", logtype = LogType.TIME)
 public int testLog01(int a, int b) {
  logger.info("进入+运算");
  return a + b;
 }
 @LogAnnotation(systemName = "计算器系统", bizCode = "-", logtype = LogType.PARAM)
 public int testLog02(int a, int b) {
  logger.info("进入-运算");
  return a - b;
 }
}

5.定义两个空类,用于区分不同类型的日志:

package myspring;
public class TimeTypeLog {
package myspring;
public class ParamTypeLog {
}

6.spring xml配置文件:

<context:component-scan base-package="myspring"/>
<aop:aspectj-autoproxy/>

7.启动spring的测试类:

package myspring;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
 public static void main(String[] args) {
  AbstractApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
  LogTest logTest = (LogTest) context.getBean("logTest");
  logTest.testLog01(1, 2);
  logTest.testLog02(3, 4);
  context.registerShutdownHook();
 }
}

8.pom

<properties>
  <spring_version>4.3.8.RELEASE</spring_version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>${spring_version}</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.8.11</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.8.11</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.7.21</version>
  </dependency>
  <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>1.1.7</version>
  </dependency>
  <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-core</artifactId>
   <version>1.1.7</version>
  </dependency>
  <dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.4</version>
  </dependency>
 </dependencies>

最后执行测试的类,日志打印如下:

使用java注解和aspectj AOP怎么实现打印日志

补充:spring boot 自定义注解实现自动打印方法日志(入参和返回值)

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.4.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.aline</groupId>
 <artifactId>demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>demo</name>
 <description>Demo project for Spring Boot</description>
 <properties>
  <java.version>1.8</java.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
  </dependency>
  <dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.7</version>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>

定义一个日志注解

SysLog.java

package com.aline.demo.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
}

定义一个日志实例缓存

LoggerCache.class
package com.aline.demo.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
public class LoggerCache {
 /**
  * 日志实例记录在内存中
  */
 private static HashMap<String, Logger> LOGERS = new HashMap<String, Logger>();
 /**
  * 根据类名获取缓存的日志实例
  * @param className 包名加类名 this.getClass().getName();
  * @return
  */
 public static Logger getLoggerByClassName(String className) {
  // 从静态map中获取日志实例
  Logger logger = LOGERS.get(className);
  // 如果没取到
  if (logger == null) {
   // 创建一个日志实例
   logger = LoggerFactory.getLogger(className);
   // 加入到静态map中
   LOGERS.put(className, logger);
  }
  // 返回
  return logger;
 }
}

定义一个切面实现日志记录

SysLogAspect.java

package com.aline.demo.aspect;
import com.alibaba.fastjson.JSON;
import com.aline.demo.util.LoggerCache;
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.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class SysLogAspect {
 @Pointcut("@annotation(com.aline.demo.annotation.SysLog)")
 public void log() {
 }
 /**
  * 加入注解自动记录方法日志
  *
  * @param joinPoint
  * @return
  * @throws Throwable
  */
 @Around(value = "log()")
 public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
  // 获取执行方法的类的名称(包名加类名)
  String className = joinPoint.getTarget().getClass().getName();
  // 获取实例和方法
  MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  Method method = signature.getMethod();
  // 从缓存中获取日志实例
  Logger log = LoggerCache.getLoggerByClassName(className);
  // 记录日志
  log.info(className + "." + method.getName() + "() 执行");
  Object[] args = joinPoint.getArgs();
  log.info("Params\t===》\t" + JSON.toJSONString(args));
  // 执行方法获取返回值
  Object proceed = joinPoint.proceed();
  // 记录日志
  log.info("Returns\t===》\t" + JSON.toJSONString(proceed));
  // 返回
  return proceed;
 } 
}

写个controller测试

TestController.java

package com.aline.demo.controller;
import com.aline.demo.annotation.SysLog;
import com.aline.demo.util.LoggerCache;
import org.slf4j.Logger;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController
@RequestMapping("/test")
public class TestController {
 static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 @GetMapping("/now")
 public String now(){
  // 从缓存中获取日志
  Logger LOG = LoggerCache.getLoggerByClassName(this.getClass().getName());
  LOG.info("自定义日志 ==》 日志内容。。。");
  return sdf.format(new Date());
 }
 @GetMapping("/hello")
 @SysLog()
 public String hello(String name){
  return "Hello, " + name;
 }
}

访问 http://localhost:8080/test/hello?name=aline

打印日志:

2019-05-09 16:58:20.410 INFO 40004 --- [nio-8080-exec-1] c.aline.demo.controller.TestController : com.aline.demo.controller.TestController.hello() 执行,参数 ==》
2019-05-09 16:58:20.584 INFO 40004 --- [nio-8080-exec-1] c.aline.demo.controller.TestController : Params ===》 ["aline"]
2019-05-09 16:58:20.598 INFO 40004 --- [nio-8080-exec-1] c.aline.demo.controller.TestController : Returns ===》 "Hello, aline"

访问 http://localhost:8080/now

打印日志:

2019-05-09 16:58:29.208 INFO 40004 --- [nio-8080-exec-3] c.aline.demo.controller.TestController : 自定义日志 ==》 日志内容。。。

以上就是使用java注解和aspectj AOP怎么实现打印日志,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI