使用注解实现AOP

117 阅读1分钟

一,创建注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyOperateLog {

}

二、创建AOP类,关联注解

@Aspect
@Component
public class LoggingAspect {
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    @Before("@annotation(org.ethh.common.annotation.StrategyOperateLog)")
    public void logExecutionTime(JoinPoint joinPoint) {
       MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
       String[] parameterNames = methodSignature.getParameterNames();
       Object[] parameterValues = joinPoint.getArgs();
       StringBuilder params = new StringBuilder();
       for (int i = 0; i < parameterNames.length; i++) {
          params.append(parameterNames[i]).append(": ").append(parameterValues[i]).append(", ");
       }
       logger.info("Executing method: {} with parameters: {}", joinPoint.getSignature().toShortString(), params.toString());
    }
    
    @AfterReturning(pointcut = "@annotation(org.ethh.common.annotation.StrategyOperateLog)", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
       logger.info("Method execution completed: {}", joinPoint.getSignature().toShortString());
       logger.info("Returned value: {}", result);
    }
    
    @AfterThrowing(pointcut = "@annotation(org.ethh.common.annotation.StrategyOperateLog)", throwing = "exception")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
       logger.error("Exception in method: {}", joinPoint.getSignature().toShortString());
       logger.error("Exception message: {}", exception.getMessage());
    }
}

之后在需要记录日志的方法上增加注解即可

@StrategyOperateLog
public ApiResponse<String> test() {
    xxx
}

三、日志配置

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<configuration>
    <property name="LOG_HOME" value="${log.home:-./logs}"/>
    <property name="LOG_APP_NAME" value="${log.app-name:-core}"/>
    <property name="MAX_SINGLE_LOG_FILE_SIZE" value="${log.max-single-log-file-size:-100MB}"/>
    <property name="MAX_LOG_FILE_HISTORY" value="${log.max-log-file-history:-180}"/>
    <property name="LOG_FILE_TOTAL_CAPACITY" value="${log.log-file-total-capacity:-10GB}"/>
    <property name="ASYNC_DISCARDING_THRESHOLD" value="${log.async.discarding-threshold:-0}"/>
    <property name="ASYNC_LOG_QUEUE_SIZE" value="${log.async.queue-size:-512}"/>

    <property name="LOG_PATTERN" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight([%X{traceId}]) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) - %cyan(%msg%n)"/>
    <property name="LOG_PATTERN_FILE" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger - %msg%n"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC_STDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>${ASYNC_DISCARDING_THRESHOLD}</discardingThreshold>
        <queueSize>${ASYNC_LOG_QUEUE_SIZE}</queueSize>
        <includeCallerData>false</includeCallerData>
        <appender-ref ref="STDOUT"/>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/${LOG_APP_NAME}.log</file>
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${LOG_APP_NAME}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
            <maxFileSize>${MAX_SINGLE_LOG_FILE_SIZE}</maxFileSize>
            <maxHistory>${MAX_LOG_FILE_HISTORY}</maxHistory>
            <totalSizeCap>${LOG_FILE_TOTAL_CAPACITY}</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN_FILE}</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>${ASYNC_DISCARDING_THRESHOLD}</discardingThreshold>
        <queueSize>${ASYNC_LOG_QUEUE_SIZE}</queueSize>
        <includeCallerData>true</includeCallerData>
        <appender-ref ref="FILE"/>
    </appender>

    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <file>${LOG_HOME}/${LOG_APP_NAME}-error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${LOG_APP_NAME}.%d{yyyy-MM-dd}-error.%i.log.zip</fileNamePattern>
            <maxFileSize>${MAX_SINGLE_LOG_FILE_SIZE}</maxFileSize>
            <maxHistory>${MAX_LOG_FILE_HISTORY}</maxHistory>
            <totalSizeCap>${LOG_FILE_TOTAL_CAPACITY}</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN_FILE}</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>${ASYNC_DISCARDING_THRESHOLD}</discardingThreshold>
        <queueSize>${ASYNC_LOG_QUEUE_SIZE}</queueSize>
        <includeCallerData>false</includeCallerData>
        <appender-ref ref="ERROR_FILE"/>
    </appender>

    <root level="INFO">
        <appender-ref ref="ASYNC_STDOUT"/>
        <appender-ref ref="ASYNC_FILE"/>
        <appender-ref ref="ASYNC_ERROR_FILE"/>
    </root>
</configuration>