RedisUtils+切面日志

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: redis常用工具类,包括string/hash/list/set基本类型操作,redisson发布订阅功能
package integration.advice;

import cn.hutool.core.util.ArrayUtil;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.google.common.collect.ImmutableMap;
import integration.util.DesensitizeUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.Map;

import static integration.util.DesensitizeUtils.encode;

/**
 * redis日志打印切面
 */
@Slf4j
@Aspect
@Component
@Order(2)
public class RedisCuts {

    @Pointcut("execution(* integration.util.redis.*.*(..))")
    public void redisCutPoint() {
    }

    @Pointcut("execution(* integration.util.redis.RedisUtils.*(..))")
    public void excludeCutPoint() {
    }

    @Around("redisCutPoint() && !excludeCutPoint()")
    public Object redisAspect(ProceedingJoinPoint pjp) {
        String method =  pjp.getTarget().getClass().getSimpleName() + "." + pjp.getSignature().getName();
        boolean needLog = checkNeedPrintLog();
        Object resp = null;
        try {
            if (redisSwitch) {
                resp = pjp.proceed();
            }
        } catch (Throwable throwable) {
            log.warn("请求缓存异常", throwable);
            resp = handlePrimitiveTypeResult(pjp);
        }
        if (needLog) {
            log.info("{} param:{} result:{}", method, getParams(pjp), resp);
        }else {
            log.info("{} param:{} result:{}", method,
                    method.contains("set") ? "noPrint" : getParams(pjp),
                    method.contains("get") ? "noPrint" : resp);
        }
        return resp;
    }

    private Object handlePrimitiveTypeResult(ProceedingJoinPoint pjp) {
        Signature signature = pjp.getSignature();
        if (signature instanceof MethodSignature){
            MethodSignature methodSignature = (MethodSignature) signature;
            Class<?> returnType = methodSignature.getMethod().getReturnType();
            if (PRIMITIVE_VALUE.containsKey(returnType)){
                return PRIMITIVE_VALUE.get(returnType);
            }
        }
        return null;
    }

    private static final Map<Class<?>, Object> PRIMITIVE_VALUE = new ImmutableMap.Builder<Class<?>, Object>()
            .put(Boolean.TYPE, false)
            .put(Integer.TYPE, 0)
            .put(Long.TYPE, 0)
            .put(Double.TYPE, 0)
            .build();


    private boolean checkNeedPrintLog() {
        if (printLogSwitch){
            return true;
        }
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        // 找到上一个方法名,带WithoutLog则无需打印日志。
        for (StackTraceElement element : stackTrace) {
            if ("integration.util.redis.RedisUtils".equals(element.getClassName())){
                return !element.getMethodName().contains("WithoutLog");
            }
        }
        return true;
    }

    private Map<String, Object> getParams(ProceedingJoinPoint pjp) {
        Map<String, Object> params = new LinkedHashMap<>();
        Object[] args = pjp.getArgs();
        String[] names = ((CodeSignature) pjp.getSignature()).getParameterNames();
        if (ArrayUtil.isNotEmpty(names) && names.length == args.length) {
            for (int i = 0; i < names.length; i++) {
                params.put(names[i], args[i]);
            }
        }
        return params;
    }

}

package integration.util.redis;

import cn.hutool.core.util.NumberUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import integration.configuration.ObjectRedisCodec;
import integration.util.JsonUtil;
import io.lettuce.core.RedisClient;
import io.lettuce.core.ScriptOutputType;
import io.lettuce.core.api.StatefulRedisConnection;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.codec.StringCodec;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;

import java.util.List;
import java.util.Map;

/**
 * 缓存工具类
 * 方法名带WithoutLog的不会打印value
 */
@Configuration
public class RedisUtils {

    private static RedisSet setRedis;
    private static RedisStr strRedis;
    private static RedisKey keyRedis;
    private static RedisList listRedis;
    private static RedisHash hashRedis;
    private static RedisScript scriptRedis;
    private static RedissonClient redissonClient;

    /* ************************************************  String  *******************************************************/

    /**
     * 同步插入缓存,过期时间单位:S
     */
    public static void setSync(String key, Object value, long timeout) {
        strRedis.set(key, JsonUtil.writeValueToString(value), timeout);
    }

    /**
     * 同步插入缓存,过期时间单位:S
     */
    public static void set(String key, Object value, long timeout) {
        strRedis.set(key, JsonUtil.writeValueToString(value), timeout);
    }

    /**
     * 同步插入缓存,过期时间单位:S
     * 返回旧value
     */
    public static String setAndGetOld(String key, Object value, long timeout) {
        String old = strRedis.getset(key, JsonUtil.writeValueToString(value));
        expire(key, timeout);
        return old;
    }

    /**
     * 异步插入缓存
     */
    public static void setAsync(String key, Object value, long timeout) {
        strRedis.setAsync(key, JsonUtil.writeValueToString(value), timeout);
    }

    /**
     * 获取缓存Str
     */
    public static String getString(String key) {
        return strRedis.get(key);
    }

    /**
     * 获取缓存Obj
     */
    public static <T> T getObject(String key, TypeReference<T> type) {
        return JsonUtil.readValue(strRedis.get(key), type);
    }

    /**
     * key存在返回false,否则返回true
     */
    public static boolean setNx(String key, String value, long exSeconds) {
        boolean result;
        if (result = strRedis.setNx(key, value)) {
            expire(key, exSeconds);
        }
        return result;
    }

    /**
     * 获取 次数
     */
    public static long getCount(String key) {
        return toLong(strRedis.get(key));
    }

    /**
     * 加 1
     */
    public static void increment(String key, long expireSeconds) {
        if (strRedis.incr(key) == 1)
            expire(key, expireSeconds);
    }

    /**
     * 减 1
     */
    public static void decrement(String key) {
        strRedis.decr(key);
    }

    /* ************************************************  Set  *********************************************************/

    /**
     * 插入set集合
     */
    public static void addSet(String key, long timeout, Object... values) {
        if (values.length == 0) return;
        setRedis.set(key, values);
        expire(key, timeout);
    }

    /**
     * 删除set中的元素
     */
    public static void remSet(String key, Object... values) {
        setRedis.del(key, values);
    }

    /**
     * 判断set中是否存在元素,若无key则返回null
     */
    public static @Nullable
    Boolean existSet(String key, Object value) {
        return keyRedis.exist(key) ? setRedis.exist(key, value) : null;
    }

    /**
     * 判断set中是否存在元素,若无key则返回false
     */
    public static boolean existSetNotNull(String key, Object value) {
        return setRedis.exist(key, value);
    }

    /* ************************************************  Hash  *********************************************************/

    /**
     * 插入map集合
     */
    public static void addHash(String hashKey, Map<String, Object> map, long timeout) {
        hashRedis.set(hashKey, map);
        expire(hashKey, timeout);
    }

    /**
     * 插入一条hash
     */
    public static void addHash(String hashKey, String field, Object value, long timeout) {
        hashRedis.set(hashKey, field, value);
        expire(hashKey, timeout);
    }

    /**
     * 插入一条hash
     */
    public static void addHashWithoutLog(String hashKey, String field, Object value, long timeout) {
        hashRedis.set(hashKey, field, value);
        expire(hashKey, timeout);
    }

    /**
     * 查询全部hash
     */
    public static <T> Map<String, T> getHash(String hashKey) {
        return hashRedis.allEntrys(hashKey);
    }

    /**
     * 查询全部hash
     */
    public static <T> Map<String, T> getHashWithoutLog(String hashKey) {
        return hashRedis.allEntrysWithoutLog(hashKey);
    }

    /**
     * 查询hash中某个key的值
     */
    public static <T> T getHash(String hashKey, String field) {
        return hashRedis.get(hashKey, field);
    }

    /**
     * 查询hash中多个key的值
     */
    public static <T> List<T> getHash(String hashKey, String... field) {
        return hashRedis.get(hashKey, field);
    }

    /**
     * 查询hash中某个key的值
     */
    public static <T> T getHashWithoutLog(String hashKey, String field) {
        return hashRedis.get(hashKey, field);
    }

    /**
     * 删除hash的keys
     */
    public static void remHash(String hashKey, String... field) {
        hashRedis.delKey(hashKey, field);
    }

    /*************************************************  List  *********************************************************/

    public static <T> void addList(String k, List<T> v, long exSeconds) {
        listRedis.pushRight(k, v);
        expire(k, exSeconds);
    }


    public static <T> List<T> getList(String k) {
        return listRedis.getAll(k);
    }

    /* ************************************************  Key  *********************************************************/

    /**
     * 设置过期时间
     */
    public static void expire(String key, long exSecond) {
        if (exSecond > 0)
            keyRedis.expire(key, exSecond);
    }

    /**
     * 返回key是否存在
     */
    public static boolean isExist(String key) {
        return keyRedis.exist(key);
    }

    /**
     * 删除key
     */
    public static long delKeys(String... keys) {
        return keyRedis.del(keys);
    }

    public static long getTtl(String key) {
        return keyRedis.ttl(key);
    }

    /**
     * 删除某个前缀的key
     */
    public static void delPattern(String pattern) {
        keyRedis.del(keyRedis.keys(pattern + "*").toArray(new String[]{}));
    }

    /* ************************************************  Scripting  ****************************************************/

    /**
     * redis调用解锁锁lua脚本
     *
     * @param keys key数组
     * @param args value数组
     */
    public static Long executeUnLockLuaScripts(ScriptOutputType type, String[] keys, String[] args) {
        return scriptRedis.evalSha(type, keys, args);
    }

    /* *******************************************  RedissonClient  *********************************************/

    public static RedissonClient getRedissonClient() {
        return redissonClient;
    }

    public static long publish(String topic, Object param) {
        return redissonClient.getTopic(topic, StringCodec.INSTANCE).publish(param);
    }

    public static void addListener(String topicId, MessageListener<String> listener) {
        RTopic topic = RedisUtils.getRedissonClient().getTopic(topicId, StringCodec.INSTANCE);
        topic.addListener(String.class, listener);
    }

    /* *******************************************  RedissonClient  *********************************************/
    /* *******************************************  private method start  *********************************************/

    private static Long toLong(String value) {
        return NumberUtil.isLong(value) ? Long.parseLong(value) : 0;
    }

    public RedisUtils(RedisList listRedis, RedisSet setRedis, RedisStr strRedis, RedisHash hashRedis, RedisKey keyRedis, RedisScript scriptRedis) {
        RedisUtils.setRedis = setRedis;
        RedisUtils.strRedis = strRedis;
        RedisUtils.keyRedis = keyRedis;
        RedisUtils.hashRedis = hashRedis;
        RedisUtils.listRedis = listRedis;
        RedisUtils.scriptRedis = scriptRedis;
    }

    public void initClient(RedisClient client, RedissonClient redissonClient) {
        StatefulRedisConnection<String, String> connection = client.connect();
        StatefulRedisConnection<String, Object> objConnection = client.connect(new ObjectRedisCodec());
        RedisStr.commands = connection.sync();
        RedisKey.commands = connection.sync();
        RedisSet.commands = objConnection.sync();
        RedisList.commands = objConnection.sync();
        RedisHash.commands = objConnection.sync();
        RedisStr.asyncCommands = connection.async();
        RedisUtils.redissonClient = redissonClient;
        RedisScript.init(connection.sync());
    }

}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.api.sync.RedisSetCommands;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * Set类型操作
 * Object需序列化
 */
@Component
@SuppressWarnings({"all"})
class RedisSet {

    static RedisSetCommands<String, Object> commands;

    /**
     * 返回所有元素
     */
    <T> Set<T> getAll(String key) {
        return (Set<T>) commands.smembers(key);
    }

    /**
     * 判断item是否为set的元素
     */
    Boolean exist(String key, Object item) {
        return commands.sismember(key, item);
    }

    /**
     * 往set添加元素并返回添加的个数
     */
    Long set(String key, Object... values) {
        return commands.sadd(key, values);
    }

    /**
     * 从set删除元素并返回删除的个数
     */
    Long del(String key, Object... values) {
        return commands.srem(key, values);
    }

    /**
     * 返回set的元素个数
     */
    Long count(String key) {
        return commands.scard(key);
    }

    /**
     * 差集
     */
    <T> Set<T> difference(String... keys) {
        return (Set<T>) commands.sdiff(keys);
    }

    /**
     * 交集
     */
    <T> Set<T> intersection(String... keys) {
        return (Set<T>) commands.sinter(keys);
    }

    /**
     * 并集
     */
    <T> Set<T> union(String... keys) {
        return (Set<T>) commands.sunion(keys);
    }


}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.api.sync.RedisHashCommands;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * Hash类型操作
 * Object需序列化
 */
@Component
@SuppressWarnings({"all"})
class RedisHash {

    static RedisHashCommands<String, Object> commands;

    /**
     * 添加多个key-value到hash中
     */
    String set(String hashKey, Map<String, Object> map) {
        return commands.hmset(hashKey, map);
    }

    /**
     * 添加key-value到hash中
     */
    Boolean set(String hashKey, String field, Object value) {
        return commands.hset(hashKey, field, value);
    }

    /**
     * 返回hash中key的值
     */
    <T> T get(String hashKey, String field) {
        return (T) commands.hget(hashKey, field);
    }

    /**
     * 返回hash中key的值
     */
    <T> T getWithoutLog(String hashKey, String field) {
        return (T) commands.hget(hashKey, field);
    }

    /**
     * 返回多个key的值
     */
    <T> List<T> get(String hashKey, String... fields) {
        return (List<T>) commands.hmget(hashKey, fields);
    }

    /**
     * 返回hash元素个数
     */
    Long getLen(String hashKey) {
        return commands.hlen(hashKey);
    }

    /**
     * 判断是否包含key的键
     */
    Boolean exist(String hashKey, String field) {
        return commands.hexists(hashKey, field);
    }

    /**
     * 返回hash中所有key
     */
    List<String> allKeys(String hashKey) {
        return commands.hkeys(hashKey);
    }

    /**
     * 返回hash中所有value
     */
    <T> List<T> allValues(String hashKey) {
        return (List<T>) commands.hvals(hashKey);
    }

    /**
     * 返回hash中所有key-value
     */
    <T> Map<String, T> allEntrys(String hashKey) {
        return (Map<String, T>) commands.hgetall(hashKey);
    }

    /**
     * 返回hash中所有key-value
     */
    <T> Map<String, T> allEntrysWithoutLog(String hashKey) {
        return (Map<String, T>) commands.hgetall(hashKey);
    }

    /**
     * 删除hash的key
     */
    Long delKey(String hashKey, String... fields) {
        return commands.hdel(hashKey, fields);
    }


}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.api.sync.RedisKeyCommands;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * String类型操作
 * Object需序列化
 */
@Component
class RedisKey {

    static RedisKeyCommands<String, String> commands;

    /**
     * key是否存在
     */
    boolean exist(String key) {
        return commands.exists(key) == 1;
    }

    /**
     * 删除keys
     */
    Long del(String... key) {
        return commands.del(key);
    }

    /**
     * 查询符合条件的key,慎用,可能会内存溢出
     */
    List<String> keys(String pattern) {
        return commands.keys(pattern);
    }

    /**
     * 设置过期时间
     */
    Boolean expire(String key, long seconds) {
        return commands.expire(key, seconds);
    }

    /**
     * 获取剩余过期时间
     */
    Long ttl(String key){
        return commands.ttl(key);
    }
}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.api.sync.RedisListCommands;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * List类型操作
 * Object需序列化
 */
@Component
@SuppressWarnings({"all"})
class RedisList {

    static RedisListCommands<String, Object> commands;

    /**
     * 返回所有元素
     */
    <T> List<T> getAll(String key) {
        return (List<T>) commands.lrange(key, start_left, start_right);
    }

    /**
     * 返回[start,end]间的元素
     */
    <T> List<T> getAll(String key, long start, long end) {
        return (List<T>) commands.lrange(key, start, end);
    }

    /**
     * 将元素添加到list左边
     */
    Long pushLeft(String key, Object... values) {
        return commands.lpush(key, values);
    }

    /**
     * 将元素添加到list右边
     */
    Long pushRight(String key, Object... v) {
        return commands.rpush(key, v);
    }

    /**
     * 从list左边弹出元素,并从list中删除
     */
    <T> T popLeft(String key) {
        return (T) commands.lpop(key);
    }

    /**
     * 从list右边弹出元素,并从list中删除
     */
    <T> T popRight(String key) {
        return (T) commands.rpop(key);
    }

    /**
     * 将元素放到指定位置
     */
    String set(String key, long index, Object value) {
        return commands.lset(key, index, value);
    }

    /**
     * 返回offset位上的元素
     */
    <T> T get(String key, long offset) {
        return (T) commands.lindex(key, offset);
    }

    /**
     * 删除list中所有的value
     */
    Long del(String key, Object value) {
        return commands.lrem(key, remove_all, value);
    }

    /**
     * 删除list中count个value
     */
    Long del(String key, long count, Object value) {
        return commands.lrem(key, count, value);
    }

    /**
     * 将原来的list缩减为[start,end]间的元素
     */
    String trim(String key, long start, long end) {
        return commands.ltrim(key, start, end);
    }


    private static final long remove_all = 0L;

    private static final long start_left = 0L;

    private static final long start_right = -1L;

}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.ScriptOutputType;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.api.sync.RedisScriptingCommands;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Scripting类型操作
 */
@Component
class RedisScript {

    static RedisScriptingCommands<String, String> commands;

    /**
     * 解锁锁lua脚本
     */
    Long evalSha(ScriptOutputType type, String[] keys, String[] args) {
        return commands.evalsha(LUA_SHA_UNLOCK.get(), type, keys, args);
    }

    static void init(RedisCommands<String, String> command){
        commands = command;
        LUA_SHA_UNLOCK.compareAndSet(null, commands.scriptLoad(UNLOCK_LUA_STATEMENT));
    }

    /**
     * 两个原子变量,用于存储加锁和解锁脚本的sha ID
     */
    private static final AtomicReference<String> LUA_SHA_UNLOCK = new AtomicReference<>();

    /**
     * lua锁脚本语句
     */
    private static final String UNLOCK_LUA_STATEMENT = "local result = redis.call('get', KEYS[1]);" +
            "if result == ARGV[1] then redis.call('del', KEYS[1]) " +
            "return 1 else return nil end";

}
package com.ph.sp.integration.util.redis;

import io.lettuce.core.SetArgs;
import io.lettuce.core.api.async.RedisStringAsyncCommands;
import io.lettuce.core.api.sync.RedisStringCommands;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * String类型操作
 * Object需序列化
 */
@Component
@SuppressWarnings({"all"})
class RedisStr {

    static RedisStringCommands<String, String> commands;
    static RedisStringAsyncCommands<String, String> asyncCommands;

    /**
     * Set the string value of a key
     */
    String set(String key, String value, long timeout) {
        SetArgs args = SetArgs.Builder.nx().ex(timeout);
        return commands.set(key, value, args);
    }
    /**
     * Set the string value of a key
     * return old value
     */
    String getset(String key, String value) {
        return commands.getset(key, value);
    }

    /**
     * Set the string value of a key with async
     */
    void setAsync(String key, String value, long timeout) {
        SetArgs args = SetArgs.Builder.nx().ex(timeout);
        asyncCommands.set(key, value, args);
    }

    String get(String key){
        return commands.get(key);
    }

    Boolean setNx(String key, String value){
        return commands.setnx(key, value);
    }

    Long incr(String key){
        return commands.incr(key);
    }

    Long decr(String key){
        return commands.decr(key);
    }



}

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
JSON Java 测试技术
为了理直气壮怼回去,写了一个日志切面输出接口出入参数
我们在日常排查问题过程中知道,入参传错是导致接口调用失败的常见原因之一。特别是提供给第三方调用的**回调接口和openAPI接口**,由于无法保证第三方开发人员的水平,经常问题不断,反反复复找你问为啥掉不通,甚至吐槽写的“啥玩意接口”,这时候你肯定一脸懵逼,怒火中烧,想展开撕逼甩锅大战,但是对方有可能是甲方金主爸爸并且你没有第一时间掌握证据证明证是对方调用的问题,你只能忍着问他是如何调接口的,卑微请求他把传参发过来看看。。。为了扭转局势,挺直腰杆怼回去:能不能靠谱点?今天我们就来讲讲系统服务中如何优雅地实现统一打印接口API参数日志,方便服务端开发快速甩锅还能拿出证据!!!
185 0
为了理直气壮怼回去,写了一个日志切面输出接口出入参数
|
Java
Java切面日志LogsAspect
Java切面日志LogsAspect
385 2
|
3月前
|
SQL 监控 Java
在IDEA 、springboot中使用切面aop实现日志信息的记录到数据库
这篇文章介绍了如何在IDEA和Spring Boot中使用AOP技术实现日志信息的记录到数据库的详细步骤和代码示例。
在IDEA 、springboot中使用切面aop实现日志信息的记录到数据库
|
5月前
|
监控 Java Spring
自定义注解+AOP切面日志+源码
自定义注解+AOP切面日志+源码
43 1
|
6月前
|
Java
java使用AOP切面获取请求日志并记录
java使用AOP切面获取请求日志并记录
|
6月前
|
Dubbo Java 应用服务中间件
微服务框架(八)Spring Boot AOP 日志切面实现
  此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。   本文为使用Spring Boot AOP 实现日志切面、分离INFO和ERROR级别日志
springBoot feign请求日志切面
springBoot feign请求日志切面
|
JSON 缓存 Java
写了个牛逼的日志切面,甩锅更方便了!
写了个牛逼的日志切面,甩锅更方便了!
85 0
写了个牛逼的日志切面,甩锅更方便了!
|
存储 运维 Java
SpringBoot使用在控制层切面注解配置的方式将日志存储在mysql
🍅程序员小王的博客:程序员小王的博客 🍅CSDN地址:程序员小王java 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 🍅java自学的学习路线:java自学的学习路线
392 0
SpringBoot使用在控制层切面注解配置的方式将日志存储在mysql
|
13天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
123 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板