千家信息网

@EnableAsync如何实现配置化日志输出

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,这篇文章主要介绍"@EnableAsync如何实现配置化日志输出",在日常操作中,相信很多人在@EnableAsync如何实现配置化日志输出问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法
千家信息网最后更新 2025年12月02日@EnableAsync如何实现配置化日志输出

这篇文章主要介绍"@EnableAsync如何实现配置化日志输出",在日常操作中,相信很多人在@EnableAsync如何实现配置化日志输出问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"@EnableAsync如何实现配置化日志输出"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

  1. 声明启动类注解、需要import的配置类。 常规情况会额外指定一下Ordered、proxyTargetClass,本例从简

    import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.context.annotation.Import;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Import(LogConfigurationImport.class)@Documentedpublic @interface EnableLog {    /**     * 指定包路径     */    String[] basePackages() default {};}


  2. 配置类中需要
    advise-> LogPointcutAdvisor : 绑定pointcut与adivce 关系。
    adivce -> LogInterceptor: 切面执行处理

    import javax.annotation.Resource;import org.springframework.aop.PointcutAdvisor;import org.springframework.context.EnvironmentAware;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.ImportAware;import org.springframework.core.Ordered;import org.springframework.core.annotation.AnnotationAttributes;import org.springframework.core.env.Environment;import org.springframework.core.task.TaskExecutor;import org.springframework.core.type.AnnotationMetadata;import org.springframework.lang.Nullable;import lombok.Setter;@Configurationpublic class LogConfigurationImport implements ImportAware, EnvironmentAware {    @Nullable    protected AnnotationAttributes enableLogAttributes;    @Setter    private Environment environment;    @Resource    TaskExecutor taskExecutor;    @Override    public void setImportMetadata(AnnotationMetadata importMetadata) {        this.enableLogAttributes = AnnotationAttributes                .fromMap(importMetadata.getAnnotationAttributes(EnableLog.class.getName(), false));        if (this.enableLogAttributes == null) {            throw new IllegalArgumentException(                    "@EnableLog is not present on importing class " + importMetadata.getClassName());        }    }    @Bean    public LogInterceptor logInterceptor(TaskExecutor taskExecutor) {        return new LogInterceptor(handler(environment), taskExecutor);    }    @Bean    public ILogHandler handler(Environment environment) {        return new LocalLogHandler(environment);    }    @Bean    public PointcutAdvisor pointcutAdvisor(LogInterceptor logInterceptor) {        LogPointcutAdvisor advisor = new LogPointcutAdvisor(this.enableLogAttributes.getStringArray("basePackages"));        advisor.setAdvice(logInterceptor);        if (enableLogAttributes != null) {            advisor.setOrder(Ordered.LOWEST_PRECEDENCE - 1);        }        return advisor;    }}----import java.util.Arrays;import java.util.List;import java.util.concurrent.ConcurrentHashMap;import org.springframework.aop.ClassFilter;import org.springframework.aop.Pointcut;import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor;import org.springframework.aop.support.ComposablePointcut;import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;import org.springframework.stereotype.Controller;import org.springframework.util.CollectionUtils;import org.springframework.web.bind.annotation.RequestMapping;import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class LogPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {    private static final long serialVersionUID = 1L;    private ComposablePointcut pointcut;  //组合方式的pointcut    public LogPointcutAdvisor(String[] basePackages) {        // 确定切面范围        pointcut = new ComposablePointcut(new AnnotationMatchingPointcut(Controller.class, RequestMapping.class, true));        if (basePackages != null && basePackages.length > 0) {            pointcut.intersection(new LogPackageFilter(Arrays.asList(basePackages)));        }    }    @AllArgsConstructor    static class LogPackageFilter  implements ClassFilter {        private List basePackages;        private final ConcurrentHashMap classMatchMap = new ConcurrentHashMap<>(50);        @Override        public boolean matches(Class clazz) {            String name = clazz.getName();            boolean match = classMatchMap.computeIfAbsent(name, key -> !CollectionUtils.isEmpty(basePackages)                    && basePackages.stream().anyMatch(t -> key.startsWith(t)));            log.debug("name: {} LogPackageFilter -> {}", name, match);            return match;        }    }    @Override    public Pointcut getPointcut() {        return this.pointcut;    }}----import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.apache.commons.lang.ArrayUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.aop.framework.AopProxyUtils;import org.springframework.core.BridgeMethodResolver;import org.springframework.core.MethodClassKey;import org.springframework.core.task.TaskExecutor;import org.springframework.lang.Nullable;import org.springframework.web.bind.annotation.RequestMapping;import com.google.common.collect.Maps;public class LogInterceptor implements MethodInterceptor {    private final Map uriCache = new ConcurrentHashMap<>(1024);    private ILogHandler logHandler;    private TaskExecutor taskExecutor;    public LogInterceptor(ILogHandler logHandler, TaskExecutor taskExecutor) {        this.logHandler = logHandler;        this.taskExecutor = taskExecutor;    }    @Override    public Object invoke(MethodInvocation invocation) throws Throwable {        long start = System.currentTimeMillis();        String exceptionMsg = null;        String exceptionType = null;        try {            Object result = invocation.proceed();            return result;        } catch (Throwable e) {            exceptionMsg = e.getMessage();            exceptionType = e.getClass().getName();            throw e;        } finally {            final String errorMsg = exceptionMsg;            final String errorType = exceptionType;            long end = System.currentTimeMillis();            taskExecutor.execute(() -> {                handLog(invocation, start, end, errorMsg, errorType);            });        }    }    private void handLog(MethodInvocation invocation, long start, long end, final String errorMsg,            final String errorType) {        Map args = null;        Method method = BridgeMethodResolver.findBridgedMethod(invocation.getMethod());        Class targetClass = getTargetClass(invocation.getThis());        String reqUrl = getRequestUrl(method, targetClass);        Parameter[] parameters = method.getParameters();        Object[] arguments = invocation.getArguments();        if (parameters != null && parameters.length > 1) {            args = Maps.newHashMapWithExpectedSize(15);            for (int i = 0; i < parameters.length; i++) {                args.put(parameters[i].getName(), i < arguments.length ? arguments[i] : null);            }        }        logHandler.handle(new LogInfo(reqUrl, method.getName(), targetClass.getName(), start, end - start, errorMsg,                errorType, args));    }    //获取对象真实的class类型    private Class getTargetClass(Object target) {        return AopProxyUtils.ultimateTargetClass(target);    }    public String getRequestUrl(Method method, @Nullable Class targetClass) {        if (method.getDeclaringClass() == Object.class) {            return null;        }        Object cacheKey = getCacheKey(method, targetClass);        String requestUrl = this.uriCache.get(cacheKey);        if (requestUrl == null) {            requestUrl = retrieveUriFromHandlerMethod(method, targetClass);            this.uriCache.put(cacheKey, requestUrl);        }        return requestUrl;    }    //通过方法获取URL    private String retrieveUriFromHandlerMethod(Method method, Class targetClass) {        RequestMapping classRequestMapping = targetClass.getAnnotation(RequestMapping.class);        StringBuilder uriSb = new StringBuilder(256);        if (classRequestMapping != null) {            String[] value = classRequestMapping.value();            if (ArrayUtils.isNotEmpty(value) && StringUtils.isNotBlank(value[0])) {                String classUri = trimFirstSlash(value[0]);                classUri = trimLastSlash(classUri);                uriSb.append(classUri);            }        }        RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);        if (methodRequestMapping != null) {            String[] value = methodRequestMapping.value();            if (ArrayUtils.isNotEmpty(value) && StringUtils.isNotBlank(value[0])) {                boolean hasClassUri = uriSb.length() != 0;                String methodUri = trimFirstSlash(value[0]);                if (hasClassUri) {                    uriSb.append("/");                }                uriSb.append(methodUri);            }        }        return uriSb.toString().replaceAll("[{}]", "");    }    private String trimFirstSlash(String uri) {        return uri.startsWith("/") ? uri.substring(1) : uri;    }    private String trimLastSlash(String uri) {        return uri.lastIndexOf("/") == uri.length() - 1 ? uri.substring(0, uri.length() - 1) : uri;    }    private Object getCacheKey(Method method, Class targetClass) {        return new MethodClassKey(method, targetClass);    }}


  3. 实际的日志操作处理类

    /** *  * 日志操作 */public interface ILogHandler {    String getAppName();    void handle(LogInfo logInfo);}import org.springframework.core.env.Environment;import com.yy.cs.base.json.Json;import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;/** *  * 本地日志输出 */@Slf4j@AllArgsConstructorpublic class LocalLogHandler implements ILogHandler {    Environment environment;    @Override    public String getAppName() {        return environment.getProperty("spring.application.name");    }    @Override    public void handle(LogInfo logInfo) {        log.info("request log: {}", Json.ObjToStr(logInfo));    }}----import java.util.Map;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructorpublic class LogInfo {    private String requestUrl;    private String method;    private String clas;    private long start;    private long cost;    private String errorMsg;    private String exceptionType;    private Map args;}


到此,关于"@EnableAsync如何实现配置化日志输出"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

日志 配置 输出 学习 切面 方法 更多 处理 帮助 实用 接下来 实际 对象 常规 情况 文章 方式 注解 理论 知识 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全保障体系架构包括 关于网络安全教育的图 金蝶标准版u盘更换服务器 网络安全和信息处置制度 网络安全与管理的基本概念 无网络连接的网络安全攻防战 广西税控盘服务器连接异常 直播需要什么网络技术 苏州网站建设软件开发 数据库传递数据中的协议有哪些 网络技术和软件与应用技术哪个难 服务器登录不上去什么意思 服务器主板可以连接机顶盒吗 把计算机设置成服务器 南京物流软件开发怎样收费 excel数据库使用技巧 现在软件开发一般学什么好点 天津数据网络技术 世界卫生组织有没有传染病数据库 泄漏 数据库 下载 奉贤区一站式软件开发欢迎选购 光明区网络技术进出口服务费 生死狙击服务器被黑客攻击 创众信息网络技术有限公司 计算机三级网络技术 知乎 多功能网络技术开发口碑推荐 管理公司用软件开发 北京交警内部服务器错误2021 网网络安全的手抄报图片 maybe数据库
0