美文网首页
设计模式导致分层—如何实现参数传递(文末附彩蛋)?

设计模式导致分层—如何实现参数传递(文末附彩蛋)?

作者: 小胖学编程 | 来源:发表于2022-03-01 17:31 被阅读0次

    一个项目/模块中,有时候会将生命周期划分成:校验层->转换层->持久化层->后置处理层。

    这样划分无疑可以使得各层级职责更加明确,但是会引入一个新的问题,即参数如何传递?

    例如:在“校验层”中需要通过IO查询校验一个字段是否合法,但是在“转换层”又需要再次使用IO查询来填充数据(“转换层”不推荐抛出异常)。

    那么为了节约性能,有两种方案:

    1. 扩展方法入参对象,这种方式可以通过泛型来实现
    2. 通过ThreadLocal来进行传递。

    无论哪一种方案,都是可以解决跨层级参数传递的问题,但是两种在后期的可读性都不是很高。

    那么有没有一种方案,既能保证了性能,又能保证可读性???

    这里说一种解决方案:隐式的ThreadLocal传递,即线程级别的缓存方案。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RequestCache {
    
    }
    
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    import javax.annotation.PostConstruct;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Service;
    import org.springframework.util.DigestUtils;
    
    import com.alibaba.fastjson.JSON;
    
    import lombok.extern.slf4j.Slf4j;
    
    /**
     *
     */
    @Service
    @Aspect
    @Slf4j
    public class RequestCacheAspect {
    
    
        private boolean openRequestCache;
    
        @ThreadLocalLifeCycle  //自定义注解,目的是自动调用remove方法,防止内存泄露
        private static ThreadLocal<Map<String, Object>> requestCache = ThreadLocal.withInitial(HashMap::new);
    
        @PostConstruct
        public void init() {
            //可读取启动参数,此处也可以读取Spring的配置参数
            openRequestCache = true;
        }
    
    
        @Around("@annotation(com.tellme.aop.RequestCache)")
        public Object doSurround(ProceedingJoinPoint point) throws Throwable {
            if (!openRequestCache) {
                return point.proceed();
            }
            MethodSignature signature = (MethodSignature) point.getSignature();
    
            Method method = signature.getMethod();
            Object[] args = point.getArgs();
            String methodName = method.getName();
            String className = method.getDeclaringClass().getSimpleName();
    
            String paramString = Stream.of(args).map(JSON::toJSONString).collect(Collectors.joining("#"));
            String cacheKey = className + "#" + methodName + "#" + paramString;
            String cacheKeyMd5 = DigestUtils.md5DigestAsHex(cacheKey.getBytes());
    
            if (!requestCache.get().containsKey(cacheKeyMd5)) {
                Object result = point.proceed();
                requestCache.get().putIfAbsent(cacheKeyMd5, result);
                return result;
            } else {
                return requestCache.get().get(cacheKeyMd5);
            }
        }
    
    }
    

    使用方式:

    @Service
    @Slf4j
    public class RequestCacheService {
    
    
        @RequestCache
        public String test(Integer id, String name) {
            log.info("执行test(Integer id, String name)方法啦");
            return String.join("$", id + "", name, new Date().toString());
        }
    
        @RequestCache
        public String test(Integer id, String name, String ex) {
            log.info("执行test(Integer id, String name, String ex)方法啦");
            return String.join("$", id + "", name, ex, new Date().toString());
        }
    }
    

    实现起来是比较简单的,即通过ThreadLocal进行线程级别的缓存。这样在第二次调用的时候,就会减少性能的损耗,且可以跨层级的去获取参数。

    彩蛋:@ThreadLocalLifeCycle注解是如何实现的,详看:https://www.jianshu.com/p/494de3bf076b

    相关文章

      网友评论

          本文标题:设计模式导致分层—如何实现参数传递(文末附彩蛋)?

          本文链接:https://www.haomeiwen.com/subject/upjdrrtx.html