千家信息网

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

发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,这篇文章主要介绍"@EnableAsync如何实现配置化日志输出",在日常操作中,相信很多人在@EnableAsync如何实现配置化日志输出问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法
千家信息网最后更新 2025年02月04日@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如何实现配置化日志输出"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0