成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何將 Dubbo Filter 攔截器原理運(yùn)用到日志攔截器中?

開發(fā) 后端
Dubbo Filter 模式非常的優(yōu)雅,以前一直只是學(xué)習(xí),沒有將其應(yīng)用到自己的項(xiàng)目中。提供的便利性是非常強(qiáng)大的,值得學(xué)習(xí)運(yùn)用。

業(yè)務(wù)背景

我們希望可以在使用日志攔截器時(shí),定義屬于自己的攔截器方法。

實(shí)現(xiàn)的方式有很多種,我們分別來看一下。

v1-基本版本

接口

最常見的定義方式,在方法執(zhí)行前后,異常,finally 提供鉤子函數(shù)。

package com.github.houbb.auto.log.api;
/**
 * autoLog 攔截器
 * @author binbin.hou
 * @since 0.0.10
 */
public interface IAutoLogInterceptor {
    /**
     * 執(zhí)行之前
     * @param interceptorContext 攔截器上下文
     * @since 0.0.10
     */
    void beforeHandle(IAutoLogInterceptorContext interceptorContext);
    /**
     * 執(zhí)行之后
     * @param interceptorContext 攔截器上下文
     * @param result 方法執(zhí)行結(jié)果
     * @since 0.0.10
     */
    void afterHandle(IAutoLogInterceptorContext interceptorContext,
                     final Object result);
    /**
     * 異常處理
     * @param interceptorContext 攔截器上下文
     * @param exception 異常
     * @since 0.0.10
     */
    void exceptionHandle(IAutoLogInterceptorContext interceptorContext, Exception exception);
    /**
     * finally 中執(zhí)行的代碼
     * @param interceptorContext 攔截器上下文
     * @since 0.0.10
     */
    void finallyHandle(IAutoLogInterceptorContext interceptorContext);
}

工具中統(tǒng)一使用攔截器

package com.github.houbb.auto.log.core.core.impl;
/**
 * @author binbin.hou
 * @since 0.0.7
 */
public class SimpleAutoLog implements IAutoLog {
    /**
     * 自動(dòng)日志輸出
     *
     * @param context 上下文
     * @return 結(jié)果
     * @since 0.0.7
     */
    @Override
    public Object autoLog(IAutoLogContext context) throws Throwable {
        //1. 日志唯一標(biāo)識(shí)
        // ... 省略
        List<IAutoLogInterceptor> autoLogInterceptors = null;
        try {
            // ... 省略其他邏輯
            // 獲取攔截器
            autoLogInterceptors = autoLogInterceptors(autoLog);


            //1.2 autoLog
            if(CollectionUtil.isNotEmpty(autoLogInterceptors)) {
                for(IAutoLogInterceptor interceptor : autoLogInterceptors) {
                    interceptor.beforeHandle(autoLogContext);
                }
            }
            //2. 執(zhí)行結(jié)果
            Object result = context.process();


            //2.1 方法執(zhí)行后
            if(CollectionUtil.isNotEmpty(autoLogInterceptors)) {
                for(IAutoLogInterceptor interceptor : autoLogInterceptors) {
                    interceptor.afterHandle(autoLogContext, result);
                }
            }
            //2.2 返回方法
            return result;
        } catch (Exception exception) {
            if(CollectionUtil.isNotEmpty(autoLogInterceptors)) {
                for(IAutoLogInterceptor interceptor : autoLogInterceptors) {
                    interceptor.exceptionHandle(autoLogContext, exception);
                }
            }
            throw new AutoLogRuntimeException(exception);
        } finally {
            // 先執(zhí)行日志
            if(CollectionUtil.isNotEmpty(autoLogInterceptors)) {
                for(IAutoLogInterceptor interceptor : autoLogInterceptors) {
                    interceptor.finallyHandle(autoLogContext);
                }
            }
        }
    }
    /**
     * 創(chuàng)建攔截器列表
     * @param autoLog 注解
     * @return 結(jié)果
     * @since 0.0.10
     */
    private List<IAutoLogInterceptor> autoLogInterceptors(final AutoLog autoLog) {
        List<IAutoLogInterceptor> resultList = new ArrayList<>();
        if(ObjectUtil.isNull(autoLog)) {
            return resultList;
        }
        Class<? extends IAutoLogInterceptor>[] interceptorClasses = autoLog.interceptor();
        if(ArrayUtil.isEmpty(interceptorClasses)) {
            return resultList;
        }
        // 循環(huán)創(chuàng)建
        for(Class<? extends IAutoLogInterceptor> clazz : interceptorClasses) {
            IAutoLogInterceptor traceIdInterceptor = createAutoLogInterceptor(clazz);
            resultList.add(traceIdInterceptor);
        }
        return resultList;
    }
    /**
     * 創(chuàng)建攔截器
     * @param clazz 類
     * @return 實(shí)體
     * @since 0.0.10
     */
    private IAutoLogInterceptor createAutoLogInterceptor(final Class<? extends IAutoLogInterceptor> clazz) {
        if(IAutoLogInterceptor.class.equals(clazz)) {
            return new AutoLogInterceptor();
        }
        return ClassUtil.newInstance(clazz);
    }
}

自定義實(shí)現(xiàn)攔截器

我們想自定義攔截器方法時(shí),只需要實(shí)現(xiàn)對應(yīng)的接口即可。

/**
 * 自定義日志攔截器
 * @author binbin.hou
 * @since 0.0.12
 */
public class MyAutoLogInterceptor extends AbstractAutoLogInterceptor {
    @Override
    protected void doBefore(AutoLog autoLog, IAutoLogInterceptorContext context) {
        System.out.println("自定義入?yún)ⅲ? + Arrays.toString(context.filterParams()));
    }
    @Override
    protected void doAfter(AutoLog autoLog, Object result, IAutoLogInterceptorContext context) {
        System.out.println("自定義出參:" + result);
    }
    @Override
    protected void doException(AutoLog autoLog, Exception exception, IAutoLogInterceptorContext context) {
        System.out.println("自定義異常:");
        exception.printStackTrace();
    }
}

方法的不足

這種方式可以實(shí)現(xiàn)常見的功能,但是依然不夠優(yōu)雅。

我們還是無法非常靈活的定義自己的攔截器實(shí)現(xiàn),就像我們使用 aop 增強(qiáng),或者 dubbo filter 一樣。

感興趣的小伙伴可以移步學(xué)習(xí)一下,此處不做展開。

Dubbo-02-dubbo invoke filter 鏈?zhǔn)秸{(diào)用原理[6]

模擬 dubbo filter

實(shí)現(xiàn) Invoker

類似 dubbo invoke,直接在以前的類中初始化即可。

AutoLogInvoker autoLogInvoker = new AutoLogInvoker(context);
Invocation invocation = new CommonInvocation();
invocation.setAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_CONTEXT, context);
invocation.setAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_START_TIME, startTimeMills);
invocation.setAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_FILTER_PARAMS, filterParams);
Invoker chainInvoker = InvokerChainBuilder.buildInvokerChain(autoLogInvoker);
Result autoLogResult = chainInvoker.invoke(invocation);

其中 AutoLogInvoker 只是對方法的執(zhí)行。

實(shí)現(xiàn)攔截器

這是的方法增強(qiáng)就是類似 dubbo filter 鏈?zhǔn)秸{(diào)用實(shí)現(xiàn)的,自定義的時(shí)候也會(huì)方便很多。

不需要拘泥于方法的執(zhí)行位置,直接編寫我們的增強(qiáng)邏輯即可。

package com.github.houbb.auto.log.core.support.interceptor.chain;
import com.alibaba.fastjson.JSON;
import com.github.houbb.auto.log.annotation.AutoLog;
import com.github.houbb.auto.log.api.IAutoLogContext;
import com.github.houbb.auto.log.core.constant.AutoLogAttachmentKeyConst;
import com.github.houbb.common.filter.annotation.FilterActive;
import com.github.houbb.common.filter.api.CommonFilter;
import com.github.houbb.common.filter.api.Invocation;
import com.github.houbb.common.filter.api.Invoker;
import com.github.houbb.common.filter.api.Result;
import com.github.houbb.common.filter.exception.CommonFilterException;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.lang.reflect.ClassUtil;
import com.github.houbb.heaven.util.lang.reflect.ReflectMethodUtil;
import com.github.houbb.id.api.Id;
import com.github.houbb.id.core.core.Ids;
import com.github.houbb.id.core.util.IdThreadLocalHelper;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import java.lang.reflect.Method;
/**
 * 默認(rèn)的日志攔截器
 */
@FilterActive(order = Integer.MIN_VALUE)
public class AutoLogCommonFilter implements CommonFilter {
    private static final Log LOG = LogFactory.getLog(AutoLogCommonFilter.class);
    /**
     * 是否需要處理日志自動(dòng)輸出
     * @param autoLog 上下文
     * @return 結(jié)果
     * @since 0.0.10
     */
    protected boolean enableAutoLog(final AutoLog autoLog) {
        if(autoLog == null) {
            return false;
        }
        return autoLog.enable();
    }
    /**
     * 獲取方法描述
     * @param method 方法
     * @param autoLog 注解
     * @return 結(jié)果
     * @since 0.0.10
     */
    protected String getMethodDescription(Method method, AutoLog autoLog) {
        String methodName = ReflectMethodUtil.getMethodFullName(method);


        if(autoLog != null
            && StringUtil.isNotEmpty(autoLog.description())) {
            methodName += "#" + autoLog.description();
        }
        return methodName;
    }
    /**
     * 獲取 traceId
     * @param autoLog 日志注解
     * @return 結(jié)果
     * @since 0.0.10
     */
    protected String getTraceId(AutoLog autoLog) {
        //1. 優(yōu)先看當(dāng)前線程中是否存在
        String oldId = IdThreadLocalHelper.get();
        if(StringUtil.isNotEmpty(oldId)) {
            return formatTraceId(oldId);
        }
        //2. 返回對應(yīng)的標(biāo)識(shí)
        Id id = getActualTraceId(autoLog);
        return formatTraceId(id.id());
    }
    /**
     * 獲取日志跟蹤號(hào)策略
     * @param autoLog 注解
     * @return 沒結(jié)果
     */
    protected Id getActualTraceId(AutoLog autoLog) {
        Class<? extends Id> idClass = autoLog.traceId();
        if(Id.class.equals(idClass)) {
            return Ids.uuid32();
        }
        return ClassUtil.newInstance(autoLog.traceId());
    }
    /**
     * 格式化日志跟蹤號(hào)
     * @param id 跟蹤號(hào)
     * @return 結(jié)果
     * @since 0.0.16
     */
    protected String formatTraceId(String id) {
        return String.format("[%s] ", id);
    }
    @Override
    public Result invoke(Invoker invoker, Invocation invocation) throws CommonFilterException {
        final IAutoLogContext autoLogContext = (IAutoLogContext) invocation.getAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_CONTEXT);
        final AutoLog autoLog = autoLogContext.autoLog();
        final boolean enableAutoLog = enableAutoLog(autoLog);
        if(!enableAutoLog) {
            return invoker.invoke(invocation);
        }
        final String description = getMethodDescription(autoLogContext.method(), autoLog);
        // 默認(rèn)從上下文中取一次
        String traceId = IdThreadLocalHelper.get();
        try {
            // 設(shè)置 traceId 策略
            if(autoLog.enableTraceId()) {
                Id id = getActualTraceId(autoLog);
                traceId = id.id();
                invocation.setAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_TRACE_ID, traceId);
                IdThreadLocalHelper.put(traceId);
            }
            Result result = invoker.invoke(invocation);
            // 日志增強(qiáng)
            logForEnhance(autoLogContext, traceId, description, result.getValue(), invocation);
            return result;
        } catch (Exception e) {
            if (autoLog.exception()) {
                String message = String.format("[TID=%s][EXCEPTION=%s]", traceId, e.getMessage());
                LOG.error(message, e);
            }
            throw new RuntimeException(e);
        }
    }
    /**
     * 增強(qiáng)日志輸出
     * @param autoLogContext 上下文
     * @param traceId 日志跟蹤號(hào)
     * @param description 方法描述
     * @param resultValue 返回值
     * @param invocation 調(diào)用上下文
     */
    private void logForEnhance(final IAutoLogContext autoLogContext,
                               final String traceId,
                               final String description,
                               final Object resultValue,
                               Invocation invocation) {
        final AutoLog autoLog = autoLogContext.autoLog();
        StringBuilder logBuilder = new StringBuilder();
        logBuilder.append(String.format("[TID=%s]", traceId));
        logBuilder.append(String.format("[METHOD=%s]", description));
        // 入?yún)?        if(autoLog.param()) {
            Object[] params = (Object[]) invocation.getAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_FILTER_PARAMS);
            logBuilder.append(String.format("[PARAM=%s]", JSON.toJSONString(params)));
        }
        // 出參
        if (autoLog.result()) {
            logBuilder.append(String.format("[RESULT=%s]", JSON.toJSONString(resultValue)));
        }
        // 耗時(shí)
        //3.1 耗時(shí) & 慢日志
        if(autoLog.costTime()) {
            long startTime = (long) invocation.getAttachment(AutoLogAttachmentKeyConst.AUTO_LOG_START_TIME);
            long costTime = System.currentTimeMillis() - startTime;
            logBuilder.append(String.format("[COST=%d ms]", costTime));
            // 慢日志
            final long slowThreshold = autoLog.slowThresholdMills();
            if(slowThreshold > 0 && costTime > slowThreshold) {
                logBuilder.append(String.format("[SLOW-THRESHOLD=%s]", slowThreshold));
            }
        }
        // 輸出日志
        LOG.info(logBuilder.toString());
    }
}

開源地址

為了便于大家學(xué)習(xí),項(xiàng)目已開源。

Github: https://github.com/houbb/auto-log

Gitee: https://gitee.com/houbinbin/auto-log

小結(jié)

dubbo filter 模式非常的優(yōu)雅,以前一直只是學(xué)習(xí),沒有將其應(yīng)用到自己的項(xiàng)目中。

提供的便利性是非常強(qiáng)大的,值得學(xué)習(xí)運(yùn)用。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2009-06-24 16:00:00

2025-05-09 08:20:50

2009-09-27 17:37:32

Hibernate攔截

2025-02-28 08:14:53

2011-05-16 10:14:11

Hibernate

2009-07-08 17:02:11

JDK實(shí)現(xiàn)調(diào)用攔截器

2011-11-21 14:21:26

SpringMVCJava框架

2009-06-25 15:54:42

Struts2教程攔截器

2020-03-25 17:55:30

SpringBoot攔截器Java

2009-06-04 08:01:25

Struts2攔截器原理

2012-02-03 13:27:16

2022-01-13 10:04:21

攔截器Interceptor過濾器

2009-02-04 14:19:38

2024-05-06 00:00:00

C#工具代碼

2013-11-04 09:35:38

Firefox插件攔截FLASH

2009-06-25 15:59:21

Struts2教程攔截器

2009-05-19 16:55:17

IE攔截器惡意軟件卡巴斯基

2021-05-17 08:11:24

Axios 開源項(xiàng)目HTTP 攔截器

2023-03-10 19:36:47

2021-11-03 17:04:11

攔截器操作Servlet
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩欧美高清 | av看片网站 | 久久国产欧美日韩精品 | 成人av鲁丝片一区二区小说 | 精品一区电影 | 九九激情视频 | 久久久久久av | 一本色道久久综合亚洲精品高清 | 羞羞的视频免费在线观看 | 久草精品视频 | 亚洲视频区 | 日韩欧美一级片 | 国产aⅴ爽av久久久久久久 | 国产午夜精品一区二区三区 | 日日碰狠狠躁久久躁96avv | 精品国产一区二区国模嫣然 | 精品一区二区av | av免费网址 | 中文字幕在线播放第一页 | 中文字幕91| jlzzjlzz国产精品久久 | 狠狠插天天干 | 久久久精品一区二区 | 久久久久久免费免费 | 久久久久久综合 | 久久综合九色综合欧美狠狠 | 一区二区三区免费观看 | 国产精品亚洲精品日韩已方 | 2022精品国偷自产免费观看 | 91精品国产乱码久久久久久久 | 黄色片在线看 | 日韩在线观看中文字幕 | 日韩高清三区 | av香蕉| 99久久免费观看 | 久久成人一区 | 8x国产精品视频一区二区 | 色婷婷婷婷色 | 小早川怜子xxxxaⅴ在线 | 久久久久国产一区二区三区四区 | 一区二区三区成人 |