温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-07-05 18:37:31 来源:亿速云 阅读:157 作者:chen 栏目:大数据

这篇文章主要介绍“@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)
    @Documented
    public @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;
    
    @Configuration
    public 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;
    
    @Slf4j
    public 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<String> basePackages;
            private final ConcurrentHashMap<String, Boolean> 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<Object, String> 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<String, Object> 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
    @AllArgsConstructor
    public 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
    @AllArgsConstructor
    public 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<String, Object> args;
    }


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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI