SpringAOP +log4J+注解的 日志管理

来源:互联网 发布:诚信荣誉 淘宝网 编辑:程序博客网 时间:2024/05/18 01:35

SpringAOP+log4J+注解 日志管理

by Kay 2017.8.10

在Spring项目中,日志管理的通常方式是采用AOP来实现,以下为我使用SpringAOP进行分类管理的一个Demo,以便总结。

代码下载:https://github.com/LiuKay/AopLog

1.pom.xml 项目依赖

<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>  <groupId>com.kay</groupId>  <artifactId>AopLog</artifactId>  <version>1.0-SNAPSHOT</version>  <packaging>jar</packaging>  <name>AopLog</name>  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <spring.version>4.1.3.RELEASE</spring.version>  </properties>  <dependencies>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-core</artifactId>      <version>${spring.version}</version>    </dependency>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context</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.6.12</version>    </dependency>    <dependency>      <groupId>org.aspectj</groupId>      <artifactId>aspectjweaver</artifactId>      <version>1.6.12</version>    </dependency>    <dependency>      <groupId>cglib</groupId>      <artifactId>cglib</artifactId>      <version>2.2</version>    </dependency>    <dependency>      <groupId>commons-logging</groupId>      <artifactId>commons-logging</artifactId>      <version>1.1.3</version>    </dependency>    <dependency>      <groupId>log4j</groupId>      <artifactId>log4j</artifactId>      <version>1.2.17</version>    </dependency>      <dependency>          <groupId>org.slf4j</groupId>          <artifactId>slf4j-api</artifactId>          <version>1.7.7</version>      </dependency>      <dependency>          <groupId>org.slf4j</groupId>          <artifactId>slf4j-log4j12</artifactId>          <version>1.7.7</version>      </dependency>      <dependency>          <groupId>com.alibaba</groupId>          <artifactId>fastjson</artifactId>          <version>1.1.41</version>      </dependency>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.11</version>      <scope>test</scope>    </dependency>  </dependencies></project>

2.项目结构

这里写图片描述

  • 基于注解的日志约定,也就是每个被切入方法需要遵循的注解写法,当然不用的话也不必这么麻烦,为了日志的格式统一;其次是通过注解可以获得额外想要获得方法信息(如方法描述,参数列表等)
  • 1)日志注解
package com.kay.annotation;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by kay on 2017/8/10. */@Retention(RetentionPolicy.RUNTIME)@Target({java.lang.annotation.ElementType.METHOD})@Documentedpublic @interface LogAnnotation {    String description() default "";}
  • 2)日志实体类,便于存放在数据库
package com.kay.entity;import java.util.Date;/** * Created by kay on 2017/8/10. */public class MyLog {    private String invokeMethod;    private String methodParams;    //private String requestIP;     // 如果是web项目可以获取ip    private Integer type;    private Date invokeTime;    private String description;    private String exceptionCode;    private String exceptionDetail;    public String getInvokeMethod() {        return invokeMethod;    }    public void setInvokeMethod(String invokeMethod) {        this.invokeMethod = invokeMethod;    }    public String getMethodParams() {        return methodParams;    }    public void setMethodParams(String methodParams) {        this.methodParams = methodParams;    }    //public String getRequestIP() {    //    return requestIP;    //}    //public void setRequestIP(String requestIP) {    //    this.requestIP = requestIP;    //}    public Integer getType() {        return type;    }    public void setType(Integer type) {        this.type = type;    }    public Date getInvokeTime() {        return invokeTime;    }    public void setInvokeTime(Date invokeTime) {        this.invokeTime = invokeTime;    }    public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }    public String getExceptionCode() {        return exceptionCode;    }    public void setExceptionCode(String exceptionCode) {        this.exceptionCode = exceptionCode;    }    public String getExceptionDetail() {        return exceptionDetail;    }    public void setExceptionDetail(String exceptionDetail) {        this.exceptionDetail = exceptionDetail;    }    @Override    public String toString() {        return "日志记录--{" +                "执行方法='" + invokeMethod + '\'' +                ", 方法参数='" + methodParams + '\'' +                ", 日志类型='" + type + '\'' +                ", 执行时间=" + invokeTime +                ", 方法描述='" + description + '\'' +                ", 异常code='" + exceptionCode + '\'' +                ", 异常详细='" + exceptionDetail + '\'' +                '}';    }}
  • 3)日志切面
package com.kay.aop;import com.alibaba.fastjson.JSON;import com.kay.annotation.LogAnnotation;import com.kay.entity.MyLog;import com.kay.service.LogService;import com.kay.service.impl.LogServiceImpl;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.lang.reflect.Method;import java.util.Date;/** * Created by kay on 2017/8/10. */@Aspectpublic class LogAspect {    //此处在实际开发中需要注入一个日志服务,模拟加入数据库    private LogService logService=new LogServiceImpl();    private  static  final Logger logger = LoggerFactory.getLogger(LogAspect. class);    private final int LOG_INFO=0;    private final int LOG_EXPETION=1;    @Before("@annotation(com.kay.annotation.LogAnnotation)")    public void logBefore(JoinPoint joinPoint){        Object[] args = joinPoint.getArgs();        StringBuilder sb = new StringBuilder();        if (args!=null) {            for (Object arg : args) {                sb.append(JSON.toJSONString(arg));            }        }        try {            //产生数据库日志            MyLog log=new MyLog();            log.setInvokeMethod(getMethodName(joinPoint));            log.setMethodParams(sb.toString());            log.setExceptionCode(null);            log.setExceptionDetail(null);            log.setType(LOG_INFO);            log.setInvokeTime(new Date());            //todo 方法描述            log.setDescription(getMthodDescription(joinPoint));            logService.addLogToDB(log);        } catch (Exception e) {            logger.error("log dobefore异常");            logger.error(e.getMessage(),e);        }        //控制台记录        getLogger(joinPoint).info(String.format("start invoke [%s], params = [%s]", new Object[]{getMethodName(joinPoint), sb.toString()}));    }    @AfterThrowing(value = "@annotation(com.kay.annotation.LogAnnotation)", throwing = "ex")    public void logAfterThrowingException(JoinPoint joinPoint,Exception ex){        Object[] args = joinPoint.getArgs();        StringBuilder sb = new StringBuilder();        if (args!=null) {            for (Object arg : args) {                sb.append(JSON.toJSONString(arg));            }        }        try {            MyLog log=new MyLog();            log.setInvokeMethod(getMethodName(joinPoint));            log.setMethodParams(sb.toString());            log.setExceptionCode(ex.getClass().getName());            log.setExceptionDetail(ex.getMessage());            log.setType(LOG_EXPETION);            log.setInvokeTime(new Date());            log.setDescription(getMthodDescription(joinPoint));            logService.addLogToDB(log);        } catch (Exception e) {           logger.error("log 异常");           logger.error(e.getMessage(),e);        }        getLogger(joinPoint).error(String.format("error occurred when invoking [%s]",new Object[]{ getMethodName(joinPoint)}), ex);    }    private Logger getLogger(JoinPoint joinPoint) {        return LoggerFactory.getLogger(getFullClassName(joinPoint));    }    private String getMethodName(JoinPoint joinPoint) {        return ((MethodSignature) joinPoint.getSignature()).getName();    }    private String getFullClassName(JoinPoint joinPoint) {        return joinPoint.getTarget().getClass().getName();    }    /**     * 获取切面方法注解上的描述     * @param joinPoint     * @return     * @throws Exception     */    public  static String getMthodDescription(JoinPoint joinPoint)            throws Exception {        String targetName = joinPoint.getTarget().getClass().getName();        String methodName = joinPoint.getSignature().getName();        Object[] arguments = joinPoint.getArgs();        Class targetClass = Class.forName(targetName);        Method[] methods = targetClass.getMethods();        String description = "";        for (Method method : methods) {            if (method.getName().equals(methodName)) {                Class[] clazzs = method.getParameterTypes();                if (clazzs.length == arguments.length) {                    description = method.getAnnotation(LogAnnotation. class).description();                    break;                }            }        }        return description;    }}
  • 4)LogService 日志服务类,模拟数据库中日志的读取
package com.kay.service.impl;import com.kay.entity.MyLog;import com.kay.service.LogService;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.List;/** * Created by kay on 2017/8/10. */@Servicepublic class LogServiceImpl implements LogService {//模拟数据库存放的日志集合    private static List<MyLog> logList=new ArrayList<MyLog>();//打印日志    public void showLogs() {        for (MyLog log:logList){            System.out.println(log);        }    }//存入日志    public void addLogToDB(MyLog log) {        logList.add(log);    }}
  • 5)BusinessService主要为模拟业务逻辑,只有一个test方法
package com.kay.service.impl;import com.kay.annotation.LogAnnotation;import com.kay.service.BusinessService;/** * Created by kay on 2017/8/10. */public class BusinessServiceImpl implements BusinessService {    @LogAnnotation(description = "test方法描述")    public String test(String param1, String param2) {        int i=1/0;  //模拟异常        System.out.println("do something...................");        return "end..";    }}
  • 6)相关配置

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:aop="http://www.springframework.org/schema/aop"       xmlns:context="http://www.springframework.org/schema/context"       xsi:schemaLocation="http://www.springframework.org/schema/beans                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd                           http://www.springframework.org/schema/aop                           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd                           http://www.springframework.org/schema/context                           http://www.springframework.org/schema/context/spring-context-3.1.xsd">    <aop:aspectj-autoproxy />    <bean id="businesService" class="com.kay.service.impl.BusinessServiceImpl" />    <bean id="advice" class="com.kay.aop.LogAspect"/>    <bean id="logService" class="com.kay.service.impl.LogServiceImpl"/></beans>

log4j.properties

log4j.rootLogger=DEBUG, A1log4j.appender.A1=org.apache.log4j.ConsoleAppenderlog4j.appender.A1.layout=org.apache.log4j.PatternLayoutlog4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
  • 7)测试方法
package com.kay;import com.kay.service.BusinessService;import com.kay.service.LogService;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainTest{    public static void main( String[] args )    {        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");        BusinessService service= (BusinessService) context.getBean("businesService");        try {            service.test("参数1", "参数2");        } catch (Exception e) {            System.out.println(e.getClass().getName());        }        LogService logService = (LogService) context.getBean("logService");        logService.showLogs();    }}
  • 8)测试结果
711  [main] INFO  com.kay.service.impl.BusinessServiceImpl  - start invoke [test], params = ["参数1""参数2"]712  [main] ERROR com.kay.service.impl.BusinessServiceImpl  - error occurred when invoking [test]java.lang.ArithmeticException: / by zero    at com.kay.service.impl.BusinessServiceImpl.test(BusinessServiceImpl.java:13)    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)    at java.lang.reflect.Method.invoke(Method.java:597)    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)    at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)    at $Proxy9.test(Unknown Source)    at com.kay.MainTest.main(MainTest.java:15)java.lang.ArithmeticException714  [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  - Returning cached instance of singleton bean 'logService'日志记录--{执行方法='test', 方法参数='"参数1""参数2"', 日志类型='0', 执行时间=Thu Aug 10 17:44:04 CST 2017, 方法描述='test方法描述', 异常code='null', 异常详细='null'}日志记录--{执行方法='test', 方法参数='"参数1""参数2"', 日志类型='1', 执行时间=Thu Aug 10 17:44:04 CST 2017, 方法描述='test方法描述', 异常code='java.lang.ArithmeticException', 异常详细='/ by zero'}

参考学习:

http://itindex.net/detail/50710-springaop-controller-service

https://github.com/Liam1206/aop-log-annotation

阅读全文
0 0
原创粉丝点击