JoinMemory 解决数据装配问题二

216 阅读12分钟

JoinInMemory 的使用

  • 业务功能接口
public interface OrderDetailService {
    List<? extends OrderDetailVO> getByUserId(Long userId);
}
  • 业务功能实现类
@Service
public class OrderDetailServiceV6 implements OrderDetailService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private JoinService joinService;

    @Override
    public List<? extends OrderDetailVO> getByUserId(Long userId) {
        List<Order> orders = this.orderRepository.getByUserId(userId);

        List<OrderDetailVOV6> orderDetailVOS = orders.stream()
                .map(order -> new OrderDetailVOV6(OrderVO.apply(order)))
                .collect(toList());

        this.joinService.joinInMemory(OrderDetailVOV6.class, orderDetailVOS);
        return orderDetailVOS;
    }
}
  • 关键注解:JoinAddressVOOnIdJoinInMemoryConfigJoinInMemory
@Data
@JoinInMemoryConfig(executorType = JoinInMemoryExecutorType.PARALLEL)
public class OrderDetailVOV6 extends OrderDetailVO {
    private final OrderVO order;

    @JoinUserVOOnId(keyFromSourceData = "#{order.userId}")
    private UserVO user;

    @JoinAddressVOOnId(keyFromSourceData = "#{order.addressId}")
    private AddressVO address;

    @JoinProductVOOnId(keyFromSourceData = "#{order.productId}")
    private ProductVO product;

}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JoinInMemory(keyFromSourceData = "",
        keyFromJoinData = "#{id}",
        loader = "#{@userRepository.getByIds(#root)}",
        joinDataConverter = "#{T(com.xdh.joininmemory.demo.UserVO).apply(#root)}"
)
public @interface JoinUserVOOnId {
    @AliasFor(
            annotation = JoinInMemory.class
    )
    String keyFromSourceData();
}

JoinInMemory 的原理

JoinInMemory 注解

  • 数据装配的核心处理流程都是:1、通过主表的主键ID查询出数据,2、拿到这些数据中作为其他表的主键的字段,3、根据步骤2取出的字段去其他表进行查询,4、将查询结果转化为需要的类型后设置到返回结果中
  • JoinMemory 解决数据装配问题一 中进行了抽象,在本篇幅中提供注解能力完成数据装配
  • keyFromSourceData 属性:指定从源数据中提取出下一步需要用到的 key,其中源数据是指:从数据库查询出来的数据、key 就是指:其他表的主键

  • keyFromJoinData 属性:如何更好描述?

  • loader 属性:指定根据 key 去查询信息的方法

  • joinDataConverter 属性:指定将数据库查询结果对象转换为返回信息需要的类型的转换方法

  • runLevel:当使用该注解需要依赖其他优先级更高的注解时,可以使用该属性指定优先级

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JoinInMemory {
    /**
     * 从 sourceData 中提取 key
     * @return
     */
    String keyFromSourceData();

    /**
     * 从 joinData 中提取 key
     * @return
     */
    String keyFromJoinData();

    /**
     * 批量数据抓取
     * @return
     */
    String loader();

    /**
     * 结果转换器
     * @return
     */
    String joinDataConverter() default "";

    /**
     * 运行级别,同一级别的 join 可 并行执行
     * @return
     */
    int runLevel() default 10;
}

JoinInMemoryConfig 注解

用于配置 JoinInMemory 注解是进行并行抓取还是串行抓取,并且可以指定并行抓取的线程池

  • JoinInMemeoryExecutorType 属性
    • 当执行【批量数据抓取】方法时,可以提供两种方式:一个是串行执行抓取方法,一个是并行执行抓取方法
    • 串行抓取:针对实时性要求不高的业务场景
    • 并行抓取:针对实时性要求高的场景,或者是当接口响应速度变慢时,可以将串行抓取变为并行抓取,从而提高响应速度
  • executorName 属性:当使用并行抓取策略的时候,可以指定线程池名字,未指定则使用默认创建的 defaultExecutor 线程池
@Override
public OrderDetail getById(Long id) {
    Order order = this.orderQueryRepository.findById(id)
            .orElse(null);
    if (order == null){
        return null;
    }
    OrderDetail orderDetail = new OrderDetail(order);
    this.joinService.joinInMemory(orderDetail);
    return orderDetail;
}

JoinService 服务接口

JoinMemory 服务对外接口

  • joinInMemory(T t) 方法:用于对单个对象进行 JoinMemory 的场景,比如:this.joinService.joinInMemory(orderDetail)
  • joinInMemory(List<> t) 方法:用于对列表数据进行 JoinMemory 的场景,比如:this.joinService.joinInMemory(orderDetailList)
public interface JoinService {
    /**
     * 执行内存 join
     * @param t
     */
    default <T> void joinInMemory(T t){
        if (t == null){
            return;
        }
        joinInMemory((Class<T>) t.getClass(), Collections.singletonList(t));
    }

    default <T> void joinInMemory(List<T> t){
        if (CollectionUtils.isEmpty(t)){
            return;
        }
        if (t.size() == 1){
            joinInMemory(t.get(0));
        }else {
            joinInMemory((Class<T>) t.get(0).getClass(), t);
        }
    }

    /**
     * 执行内存 Join
     * @param tCls 实际类型
     * @param t 需要抓取的集合
     */
    <T> void joinInMemory(Class<T> tCls, List<T> t);

    /**
     * 注册一个类型,主要用于初始化
     * @param tCls
     * @param <T>
     */
    <T> void register(Class<T> tCls);
}

DefaultJoinService 实现类

JoinService 的实现类

  • 核心关注点有下面几个

    • DefaultJoinService 构造函数传入了 JoinItemsExecutorFactory
    • JoinItemsExecutorFactory 一个工厂类,其具体作用后续讲解
    • joinInMemory 方法:通过 createJoinExecutorGroup 方法获取到一个 JoinItemsExecutor,并执行 execute 方法
    • createJoinExecutorGroup 方法:通过构造函数传入的 JoinItemsExecutorFactory,调用其 createFor 方法,得到 JoinItemsExecutor
  • 那么根据上面的几个关注点,可以从下面几个思路去理解实现原理

    • DefaultJoinService 的构造函数在哪里使用了?
      • 见 JoinInMemoryAutoConfiguration
    • JoinItemsExecutorFactory 的 createFor 方法的逻辑是什么?
      • 见 DefaultJoinItemsExecutorFactory
    • JoinItemsExecutor 的 execute 方法的逻辑是什么?
      • 见 AbstractJoinItemsExecutor、ParallelJoinItemsExecutor、SerialJoinItemsExecutor
public class DefaultJoinService implements JoinService {
    private final JoinItemsExecutorFactory joinItemsExecutorFactory;

    /**
     * 缓存,避免频繁的初始化
     */
    private final Map<Class, JoinItemsExecutor> cache = Maps.newConcurrentMap();

    public DefaultJoinService(JoinItemsExecutorFactory joinItemsExecutorFactory) {
        this.joinItemsExecutorFactory = joinItemsExecutorFactory;
    }

    @Override
    public <T> void joinInMemory(Class<T> tCls, List<T> t) {
        this.cache.computeIfAbsent(tCls, this::createJoinExecutorGroup)
                .execute(t);
    }

    @Override
    public <T> void register(Class<T> tCls) {
        this.cache.computeIfAbsent(tCls, this::createJoinExecutorGroup);
    }

    private JoinItemsExecutor createJoinExecutorGroup(Class aClass) {
        return this.joinItemsExecutorFactory.createFor(aClass);
    }
}

JoinInMemoryAutoConfiguration

注入相关 Bean

  • @ConditionalOnMissingBean 是一个条件注解,它的作用是在满足条件的情况下,使注解的组件(Bean)生效
    • 具体来说,当一个组件使用了 @ConditionalOnMissingBean 注解时,它的生效与否将受到当前 Spring 上下文中是否存在该类型的 Bean 的影响。如果当前上下文中不存在该类型的 Bean,则被注解的组件将被创建并注册为一个 Bean;如果已经存在了同类型的 Bean,则被注解的组件将不会被创建。
    • 这个注解常用于配置类或者自定义的配置文件中,用于控制某个特定的 Bean 在不存在时进行配置
  • 注入 JoinItemsExecutorFactory:通过创建 DefaultJoinItemsExecutorFactory 得到
  • 注入 JoinService:通过创建 DefaultJoinService 对象得到
  • 注入 defaultExecutor:这个就是 JoinInMemoryConfig 注解中提供的默认线程池
  • 注入 JoinInMemoryBasedJoinItemExecutorFactory?
@Configuration
@Slf4j
public class JoinInMemoryAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public JoinItemsExecutorFactory joinItemsExecutorFactory(Collection<? extends JoinItemExecutorFactory> joinItemExecutorFactories,
                                                             Map<String, ExecutorService> executorServiceMap){
        return new DefaultJoinItemsExecutorFactory(joinItemExecutorFactories, executorServiceMap);
    }

    @Bean
    @ConditionalOnMissingBean
    public JoinService joinService(JoinItemsExecutorFactory joinItemsExecutorFactory){
        return new DefaultJoinService(joinItemsExecutorFactory);
    }

    @Bean
    public JoinInMemoryBasedJoinItemExecutorFactory joinInMemoryBasedJoinItemExecutorFactory(ApplicationContext applicationContext){
        return new JoinInMemoryBasedJoinItemExecutorFactory(new BeanFactoryResolver(applicationContext));
    }

    @Bean
    public ExecutorService defaultExecutor(){
        BasicThreadFactory basicThreadFactory = new BasicThreadFactory.Builder()
                .namingPattern("JoinInMemory-Thread-%d")
                .daemon(true)
                .build();
        int maxSize = Runtime.getRuntime().availableProcessors() * 3;
        return new ThreadPoolExecutor(0, maxSize,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                basicThreadFactory,
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

}

JoinItemsExecutorFactory 和 DefaultJoinItemsExecutorFactory

JoinItemsExecutorFactory

  • 工厂类,从 class 中解析信息,并创建 JoinItemsExecutor

DefaultJoinItemsExecutorFactory

  • 使用 JoinItemExecutorFactory 为每个 Join 数据 创建 JoinItemExecutor
  • 将一个 class 的 JoinItemExecutor 封装成 JoinItemsExecutor
  • 核心关注点有下面几个
    • createFor 方法:通过 JoinItemExecutorFactory 拿到一系列的 JoinItemExecutor,再读取 JoinInMemoryConfig 注解配置的 JoinInMemeoryExecutorType,然后根据 JoinItemExecutorJoinInMemeoryExecutorType 创建 JoinItemsExecutor 对象
    • buildJoinItemsExecutor 方法:根据 JoinInMemeoryExecutorType 创建 JoinItemsExecutor 对象
    • createForType 方法:见 JoinItemExecutorFactory
public interface JoinItemsExecutorFactory {
    /**
     * 为 类 创建 Join 执行器
     * @param cls
     * @param <D>
     * @return
     */
    <D> JoinItemsExecutor<D> createFor(Class<D> cls);
}
@Slf4j
public class DefaultJoinItemsExecutorFactory implements JoinItemsExecutorFactory {
    private final List<JoinItemExecutorFactory> joinItemExecutorFactories;
    private final Map<String, ExecutorService> executorServiceMap;

    public DefaultJoinItemsExecutorFactory(Collection<? extends JoinItemExecutorFactory> joinItemExecutorFactories,
                                           Map<String, ExecutorService> executorServiceMap) {
        this.joinItemExecutorFactories = Lists.newArrayList(joinItemExecutorFactories);

        // 按执行顺序进行排序
        AnnotationAwareOrderComparator.sort(this.joinItemExecutorFactories);
        this.executorServiceMap = executorServiceMap;
    }


    @Override
    public <D> JoinItemsExecutor<D> createFor(Class<D> cls) {
        // 依次遍历 JoinItemExecutorFactory, 收集 JoinItemExecutor 信息
        List<JoinItemExecutor<D>> joinItemExecutors = this.joinItemExecutorFactories.stream()
                .flatMap(factory -> factory.createForType(cls).stream())
                .collect(Collectors.toList());

        // 从 class 上读取配置信息
        JoinInMemoryConfig joinInMemoryConfig = cls.getAnnotation(JoinInMemoryConfig.class);

        // 封装为 JoinItemsExecutor
        return buildJoinItemsExecutor(cls, joinInMemoryConfig, joinItemExecutors);
    }

    private  <D> JoinItemsExecutor<D> buildJoinItemsExecutor(Class<D> cls, JoinInMemoryConfig joinInMemoryConfig, List<JoinItemExecutor<D>> joinItemExecutors){
        // 使用 串行执行器
        if(joinInMemoryConfig == null || joinInMemoryConfig.executorType() == JoinInMemoryExecutorType.SERIAL){
            log.info("JoinInMemory for {} use serial executor", cls);
            return new SerialJoinItemsExecutor<>(cls, joinItemExecutors);
        }

        // 使用 并行执行器
        if (joinInMemoryConfig.executorType() == JoinInMemoryExecutorType.PARALLEL){
            log.info("JoinInMemory for {} use parallel executor, pool is {}", cls, joinInMemoryConfig.executorName());
            // 获取线程池
            ExecutorService executor = executorServiceMap.get(joinInMemoryConfig.executorName());
            Preconditions.checkArgument(executor != null);
            return new ParallelJoinItemsExecutor<>(cls, joinItemExecutors, executor);
        }
        throw new IllegalArgumentException();
    }
}

JoinItemsExecutor、AbstractJoinItemsExecutor、SerialJoinItemsExecutor、ParallelJoinItemsExecutor

JoinItemsExecutor 执行器接口,抽象实现类以及具体实现类

  • JoinItemsExecutor 执行器接口
public interface JoinItemsExecutor<DATA> {
    void execute(List<DATA> datas);
}
  • AbstractJoinItemsExecutor:JoinItemsExecutor 的抽象实现,主要是在构造函数中对所有的 JoinItemExecutor 按照 runLevel 进行优先级排序
abstract class AbstractJoinItemsExecutor<DATA> implements JoinItemsExecutor<DATA> {
    @Getter(AccessLevel.PROTECTED)
    private final Class<DATA> dataCls;
    @Getter(AccessLevel.PROTECTED)
    private final List<JoinItemExecutor<DATA>> joinItemExecutors;

    public AbstractJoinItemsExecutor(Class<DATA> dataCls,
                                     List<JoinItemExecutor<DATA>> joinItemExecutors) {
        Preconditions.checkArgument(dataCls != null);
        Preconditions.checkArgument(joinItemExecutors != null);

        this.dataCls = dataCls;
        this.joinItemExecutors = joinItemExecutors;
        Collections.sort(this.joinItemExecutors, Comparator.comparingInt(JoinItemExecutor::runOnLevel));
    }
}
  • SerialJoinItemsExecutor:串行执行器,JoinItemsExecutor 接口的具体实现,多个 join 操作顺序执行
/**
 * 串行执行器,多个 join 操作顺序执行
 */
@Slf4j
public class SerialJoinItemsExecutor<DATA> extends AbstractJoinItemsExecutor<DATA> {
    public SerialJoinItemsExecutor(Class<DATA> dataCls,
                                   List<JoinItemExecutor<DATA>> joinItemExecutors) {
        super(dataCls, joinItemExecutors);
    }

    @Override
    public void execute(List<DATA> datas) {
        getJoinItemExecutors().forEach(dataJoinExecutor -> {
            log.debug("run join on level {} use {}",
                    dataJoinExecutor.runOnLevel(), dataJoinExecutor);
            if (log.isDebugEnabled()){
                StopWatch stopWatch = StopWatch.createStarted();
                dataJoinExecutor.execute(datas);
                stopWatch.stop();

                log.debug("run execute cost {} ms, executor is {}, data is {}.",
                        stopWatch.getTime(TimeUnit.MILLISECONDS),
                        dataJoinExecutor,
                        datas);
            }else {
                dataJoinExecutor.execute(datas);
            }

        });
    }
}
  • ParallelJoinItemsExecutor:并行执行器,利用配置的线程池,采用多线程方式去执行 join,同一 level 的 join 在线程中并行执行
/**
 * 并行执行器,同一 level 的 join 在线程中并行执行
 */
@Slf4j
public class ParallelJoinItemsExecutor<DATA> extends AbstractJoinItemsExecutor<DATA> {
    private final ExecutorService executor;
    private final List<JoinExecutorWithLevel> joinExecutorWithLevel;
    public ParallelJoinItemsExecutor(Class<DATA> dataCls,
                                     List<JoinItemExecutor<DATA>> joinItemExecutors,
                                     ExecutorService executor) {
        super(dataCls, joinItemExecutors);
        this.executor = executor;
        this.joinExecutorWithLevel = buildJoinExecutorWithLevel();
    }

    private List<JoinExecutorWithLevel> buildJoinExecutorWithLevel() {
        List<JoinExecutorWithLevel> collect = getJoinItemExecutors().stream()
                .collect(Collectors.groupingBy(joinExecutor -> joinExecutor.runOnLevel()))
                .entrySet().stream()
                .map(entry -> new JoinExecutorWithLevel(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        // 根据 level 进行排序,解决依赖问题
        Collections.sort(collect, Comparator.comparingInt(o -> o.level));
        return collect;
    }

    @Override
    public void execute(List<DATA> datas) {
        this.joinExecutorWithLevel.forEach(joinExecutorWithLevel1 -> {
            log.debug("run join on level {} use {}", joinExecutorWithLevel1.getLevel(),
                    joinExecutorWithLevel1.getJoinItemExecutors());

            List<Task> tasks = buildTasks(joinExecutorWithLevel1, datas);
            try {
                if (log.isDebugEnabled()) {
                    StopWatch stopWatch = StopWatch.createStarted();
                    this.executor.invokeAll(tasks);
                    stopWatch.stop();

                    log.debug("run execute cost {} ms, task is {}.",
                            stopWatch.getTime(TimeUnit.MILLISECONDS),
                            tasks);
                }else {
                    this.executor.invokeAll(tasks);
                }
            } catch (InterruptedException e) {
                log.error("invoke task {} interrupted", tasks, e);
            }
        });
    }

    private List<Task> buildTasks(JoinExecutorWithLevel joinExecutorWithLevel, List<DATA> datas) {
        return joinExecutorWithLevel.getJoinItemExecutors().stream()
                .map(joinExecutor -> new Task(joinExecutor, datas))
                .collect(Collectors.toList());
    }

    @Value
    class Task implements Callable<Void> {
        private final JoinItemExecutor<DATA> joinItemExecutor;
        private final List<DATA> datas;

        @Override
        public Void call() throws Exception {
            this.joinItemExecutor.execute(this.datas);
            return null;
        }
    }

    @Value
    class JoinExecutorWithLevel{
        private final Integer level;
        private final List<JoinItemExecutor<DATA>> joinItemExecutors;
    }
}

JoinItemExecutorFactory、AbstractAnnotationBasedJoinItemExecutorFactory、JoinInMemoryBasedJoinItemExecutorFactory

  • JoinItemExecutorFactory:为一个类生成一组 JoinMemory 执行器
/**
 * 为一个类生成一组 JoinMemory 执行器
 */
public interface JoinItemExecutorFactory {
    <DATA> List<JoinItemExecutor<DATA>> createForType(Class<DATA> cls);
}
  • AbstractAnnotationBasedJoinItemExecutorFactory:JoinItemExecutorFactory 的抽象实现类
  • 核心关注点
    • createForField 方法:见 JoinItemExecutor、AbstractJoinItemExecutor、JoinItemExecutorAdapter
/**
 * JoinItemExecutorFactory 的实现类,并定义一些抽象方法,用于生成 Function、BiConsumer
 * 通过传入的 Class 类,获取该类的所有字段,并获取字段上的使用到 JoinInMemory 注解
 * 通过 JoinItemExecutorAdapter 获取到所有使用到了 JoinInMemory 注解的字段的 JoinInMemory 处理器
 */
abstract class AbstractAnnotationBasedJoinItemExecutorFactory<A extends Annotation>
    implements JoinItemExecutorFactory {
    private final Class<A> annotationCls;

    protected AbstractAnnotationBasedJoinItemExecutorFactory(Class<A> annotationCls) {
        this.annotationCls = annotationCls;
    }

    @Override
    public <DATA> List<JoinItemExecutor<DATA>> createForType(Class<DATA> cls) {
        // 从 字段 上获取 注解,并将其转换为 JoinItemExecutor
        List<Field> fieldsListWithAnnotation = FieldUtils.getAllFieldsList(cls);

        // 为每一个字段创建一个执行器
        return fieldsListWithAnnotation.stream()
                .map(field -> createForField(cls, field,
                        AnnotatedElementUtils.findMergedAnnotation(field, annotationCls))
                ).filter(Objects::nonNull)
                .collect(toList());
    }

    private <DATA> JoinItemExecutor<DATA> createForField(Class<DATA> cls, Field field,A ann) {
        if (ann == null){
            return null;
        }
        JoinItemExecutorAdapter adapter = JoinItemExecutorAdapter.builder()
                .name(createName(cls, field, ann))
                .runLevel(createRunLevel(cls, field, ann))
                .keyFromSourceData(createKeyGeneratorFromData(cls, field, ann))
                .joinDataLoader(createDataLoader(cls, field, ann))
                .keyFromJoinData(createKeyGeneratorFromJoinData(cls, field, ann))
                .joinDataConverter(createDataConverter(cls, field, ann))
                .foundCallback(createFoundFunction(cls, field, ann))
                .lostCallback(createLostFunction(cls, field, ann))
                .build();

        return adapter;
    }

    protected <DATA> BiConsumer<Object, Object> createLostFunction(Class<DATA> cls, Field field, A ann){
        return null;
    }

    protected abstract <DATA> BiConsumer<Object, List<Object>> createFoundFunction(Class<DATA> cls, Field field, A ann);

    protected abstract <DATA> Function<Object, Object> createDataConverter(Class<DATA> cls, Field field, A ann);

    protected abstract <DATA> Function<Object, Object> createKeyGeneratorFromJoinData(Class<DATA> cls, Field field, A ann);

    protected abstract <DATA> Function<List<Object>, List<Object>> createDataLoader(Class<DATA> cls, Field field, A ann);

    protected abstract <DATA> Function<Object, Object> createKeyGeneratorFromData(Class<DATA> cls, Field field, A ann);

    protected abstract <DATA> int createRunLevel(Class<DATA> cls, Field field, A ann);

    protected <DATA> String createName(Class<DATA> cls, Field field, A ann){
        return new StringBuilder()
                .append("class[").append(cls.getSimpleName()).append("]")
                .append("#field[").append(field.getName()).append("]")
                .append("-").append(ann.getClass().getSimpleName())
                .toString();
    }
}
  • AbstractAnnotationBasedJoinItemExecutorFactory
  • 核心关注点
    • Function:Function<T, R> 接口表示一个接受参数类型为 T 的对象,并返回结果类型为 R 的对象的函数。它定义了 apply() 方法,用于执行具体的函数逻辑。常见的函数式接口方法有:andThen()、compose() 和 identity()
    • BiConsumer:BiConsumer<T, U> 接口表示一个接受两个参数类型分别为 T 和 U 的对象,并不返回结果的操作。它定义了 accept() 方法,用于执行具体的操作逻辑
    • Spring Expression Language:SpEL你感兴趣的实现原理浅析
/**
 * 继承 AbstractAnnotationBasedJoinItemExecutorFactory 类,实现其抽象方法
 * 抽象方法的实现原理:根据 JoinInMemory 的属性 + Spring表达式语言(Spring Expression Language),生成相应的 Function 和 BiConsumer
 */
@Slf4j
public class JoinInMemoryBasedJoinItemExecutorFactory extends AbstractAnnotationBasedJoinItemExecutorFactory<JoinInMemory>{
    private final ExpressionParser parser = new SpelExpressionParser();
    private final TemplateParserContext templateParserContext = new TemplateParserContext();
    private final BeanResolver beanResolver;

    public JoinInMemoryBasedJoinItemExecutorFactory(BeanResolver beanResolver) {
        super(JoinInMemory.class);
        this.beanResolver = beanResolver;
    }


    @Override
    protected <DATA> BiConsumer<Object, List<Object>> createFoundFunction(Class<DATA> cls, Field field, JoinInMemory ann) {
        log.info("write field is {} for class {}", field.getName(), cls);
        boolean isCollection = Collection.class.isAssignableFrom(field.getType());
        return new DataSetter(field.getName(), isCollection);
    }

    @Override
    protected <DATA> Function<Object, Object> createDataConverter(Class<DATA> cls, Field field, JoinInMemory ann) {
        if (StringUtils.isEmpty(ann.joinDataConverter())){
            log.info("No Data Convert for class {}, field {}", cls, field.getName());
            return Function.identity();
        }else {
            log.info("Data Convert is {} for class {}, field {}", ann.joinDataConverter(), cls, field.getName());
            return new DataGetter(ann.joinDataConverter());
        }
    }

    @Override
    protected <DATA> Function<Object, Object> createKeyGeneratorFromJoinData(Class<DATA> cls, Field field, JoinInMemory ann) {
        log.info("Key from join data is {} for class {}, field {}",
                ann.keyFromJoinData(), cls, field.getName());
        return new DataGetter(ann.keyFromJoinData());
    }

    @Override
    protected <DATA> Function<List<Object>, List<Object>> createDataLoader(Class<DATA> cls, Field field, JoinInMemory ann) {
        log.info("data loader is {} for class {}, field {}",
                ann.loader(), cls, field.getName());
        return new DataGetter(ann.loader());
    }

    @Override
    protected <DATA> Function<Object, Object> createKeyGeneratorFromData(Class<DATA> cls, Field field, JoinInMemory ann) {
        log.info("Key from source data is {} for class {}, field {}",
                ann.keyFromJoinData(), cls, field.getName());
        return new DataGetter(ann.keyFromSourceData());
    }

    @Override
    protected <DATA> int createRunLevel(Class<DATA> cls, Field field, JoinInMemory ann) {
        log.info("run level is {} for class {}, field {}",
                ann.runLevel(), cls, field.getName());
        return ann.runLevel();
    }

    private class DataSetter<T, U> implements BiConsumer<Object, List<Object>>{
        private final String fieldName;
        private final boolean isCollection;
        private final Expression expression;

        private DataSetter(String fieldName, boolean isCollection) {
            this.fieldName = fieldName;
            this.expression = parser.parseExpression(fieldName);
            this.isCollection = isCollection;
        }

        @Override
        public void accept(Object data, List<Object> result) {
            if (isCollection) {
                this.expression.setValue(data, result);
            }else {
                int size = result.size();
                if (size == 1){
                    this.expression.setValue(data, result.get(0));
                }else {
                    log.warn("write join result to {} error, field is {}, data is {}",
                            data,
                            fieldName,
                            result);
                }
            }
        }
    }

    private class DataGetter<T, R> implements Function<T, R>{
        private final String expStr;
        private final Expression expression;
        private final EvaluationContext evaluationContext;

        private DataGetter(String expStr) {
            this.expStr = expStr;
            this.expression = parser.parseExpression(expStr, templateParserContext);
            StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
            evaluationContext.setBeanResolver(beanResolver);
            this.evaluationContext = evaluationContext;
        }

        @Override
        public Object apply(Object data) {
            if (data == null){
                return null;
            }

            return expression.getValue(evaluationContext, data);
        }
    }
}

JoinItemExecutor、AbstractJoinItemExecutor、JoinItemExecutorAdapter

JoinMemory 执行器,JoinMemory 执行器的抽象实现类,模板方法的适配器

/**
 * JoinMemory 执行器:执行数据 join 操作
 */
public interface JoinItemExecutor<DATA> {
    void execute(List<DATA> datas);

    default int runOnLevel(){
        return 0;
    }
}
/**
 * JoinMemory 执行器的抽象实现类:定义抽象方法,并在 execute 中编排后执行
 *
 * @param <SOURCE_DATA> 原始数据
 * @param <JOIN_KEY> join 使用的 key
 * @param <JOIN_DATA> join 获取的 数据
 * @param <JOIN_RESULT> 转换后的结果数据
 */
@Slf4j
abstract class AbstractJoinItemExecutor<SOURCE_DATA, JOIN_KEY, JOIN_DATA, JOIN_RESULT> implements JoinItemExecutor<SOURCE_DATA> {

    /**
     * 从原始数据中生成 JoinKey
     * @param data
     * @return
     */
    protected abstract JOIN_KEY createJoinKeyFromSourceData(SOURCE_DATA data);

    /**
     * 根据 JoinKey 批量获取 JoinData
     * @param joinKeys
     * @return
     */
    protected abstract List<JOIN_DATA> getJoinDataByJoinKeys(List<JOIN_KEY> joinKeys);

    /**
     * 从 JoinData 中获取 JoinKey
     * @param joinData
     * @return
     */
    protected abstract JOIN_KEY createJoinKeyFromJoinData(JOIN_DATA joinData);

    /**
     * 将 JoinData 转换为 JoinResult
     * @param joinData
     * @return
     */
    protected abstract JOIN_RESULT convertToResult(JOIN_DATA joinData);

    /**
     * 将 JoinResult 写回至 SourceData
     * @param data
     * @param JoinResults
     */
    protected abstract void onFound(SOURCE_DATA data, List<JOIN_RESULT> JoinResults);

    /**
     * 未找到对应的 JoinData
     * @param data
     * @param joinKey
     */
    protected abstract void onNotFound(SOURCE_DATA data, JOIN_KEY joinKey);

    @Override
    public void execute(List<SOURCE_DATA> sourceDatas) {
        // 从源数据中提取 JoinKey
        List<JOIN_KEY> joinKeys = sourceDatas.stream()
                .filter(Objects::nonNull)
                .map(this::createJoinKeyFromSourceData)
                .filter(Objects::nonNull)
                .distinct()
                .collect(toList());
        log.debug("get join key {} from source data {}", joinKeys, sourceDatas);

        // 根据 JoinKey 获取 JoinData
        List<JOIN_DATA> allJoinDatas = getJoinDataByJoinKeys(joinKeys);
        log.debug("get join data {} by join key {}", allJoinDatas, joinKeys);

        // 将 JoinData 以 Map 形式进行组织
        Map<JOIN_KEY, List<JOIN_DATA>> joinDataMap = allJoinDatas.stream()
                .filter(Objects::nonNull)
                .collect(groupingBy(this::createJoinKeyFromJoinData));
        log.debug("group by join key, result is {}", joinDataMap);

        // 处理每一条 SourceData
        for (SOURCE_DATA data : sourceDatas){
            // 从 SourceData 中 获取 JoinKey
            JOIN_KEY joinKey = createJoinKeyFromSourceData(data);
            if (joinKey == null){
                log.warn("join key from join data {} is null", data);
                continue;
            }
            // 根据 JoinKey 获取 JoinData
            List<JOIN_DATA> joinDatasByKey = joinDataMap.get(joinKey);
            if (CollectionUtils.isNotEmpty(joinDatasByKey)){
                // 获取到 JoinData, 转换为 JoinResult,进行数据写回
                List<JOIN_RESULT> joinResults = joinDatasByKey.stream()
                        .filter(Objects::nonNull)
                        .map(joinData -> convertToResult(joinData))
                        .collect(toList());

                log.debug("success to convert join data {} to join result {}", joinDatasByKey, joinResults);
                onFound(data, joinResults);
                log.debug("success to write join result {} to source data {}", joinResults, data);
            }else {
                log.warn("join data lost by join key {} for source data {}", joinKey, data);
                // 为获取到 JoinData,进行 notFound 回调
                onNotFound(data, joinKey);
            }
        }
    }
}
/**
 * 模板方法的适配器
 * 
 * JoinMemory 执行器的实现类:实现 AbstractJoinItemExecutor 中的抽象方法
 * 通过 JoinItemExecutorAdapter 构造器的入参,传入要实现的抽象方法的实现逻辑(Function、BiConsumer)
 * 在 AbstractAnnotationBasedJoinItemExecutorFactory 中调用了构造器
 */
@Slf4j
@Builder
@Getter
public class JoinItemExecutorAdapter<SOURCE_DATA, JOIN_KEY, JOIN_DATA, RESULT>
        extends AbstractJoinItemExecutor<SOURCE_DATA, JOIN_KEY, JOIN_DATA, RESULT> {
    private final String name;
    private final int runLevel;

    private final Function<SOURCE_DATA, JOIN_KEY> keyFromSourceData;
    private final Function<List<JOIN_KEY>, List<JOIN_DATA>> joinDataLoader;
    private final Function<JOIN_DATA, JOIN_KEY> keyFromJoinData;
    private final Function<JOIN_DATA, RESULT> joinDataConverter;
    private final BiConsumer<SOURCE_DATA, List<RESULT>> foundCallback;
    private final BiConsumer<SOURCE_DATA, JOIN_KEY> lostCallback;


    public JoinItemExecutorAdapter(String name,
                                   Integer runLevel,
                                   Function<SOURCE_DATA, JOIN_KEY> keyFromSourceData,
                                   Function<List<JOIN_KEY>, List<JOIN_DATA>> joinDataLoader,
                                   Function<JOIN_DATA, JOIN_KEY> keyFromJoinData,
                                   Function<JOIN_DATA, RESULT> joinDataConverter,
                                   BiConsumer<SOURCE_DATA, List<RESULT>> foundCallback,
                                   BiConsumer<SOURCE_DATA, JOIN_KEY> lostCallback) {

        Preconditions.checkArgument(keyFromSourceData != null);
        Preconditions.checkArgument(joinDataLoader != null);
        Preconditions.checkArgument(keyFromJoinData != null);
        Preconditions.checkArgument(joinDataConverter != null);
        Preconditions.checkArgument(foundCallback != null);

        this.name = name;
        this.keyFromSourceData = keyFromSourceData;
        this.joinDataLoader = joinDataLoader;
        this.keyFromJoinData = keyFromJoinData;
        this.joinDataConverter = joinDataConverter;
        this.foundCallback = foundCallback;

        if (lostCallback != null) {
            this.lostCallback = getDefaultLostFunction().andThen(lostCallback);
        }else {
            this.lostCallback = getDefaultLostFunction();
        }

        if (runLevel == null){
            this.runLevel = 0;
        }else {
            this.runLevel = runLevel.intValue();
        }
    }

    @Override
    protected JOIN_KEY createJoinKeyFromSourceData(SOURCE_DATA data) {
        return this.keyFromSourceData.apply(data);
    }

    @Override
    protected List<JOIN_DATA> getJoinDataByJoinKeys(List<JOIN_KEY> joinKeys) {
        return this.joinDataLoader.apply(joinKeys);
    }

    @Override
    protected JOIN_KEY createJoinKeyFromJoinData(JOIN_DATA joinData) {
        return this.keyFromJoinData.apply(joinData);
    }

    @Override
    protected RESULT convertToResult(JOIN_DATA joinData) {
        return this.joinDataConverter.apply(joinData);
    }

    @Override
    protected void onFound(SOURCE_DATA data, List<RESULT> JoinResults) {
        this.foundCallback.accept(data, JoinResults);
    }

    @Override
    protected void onNotFound(SOURCE_DATA data, JOIN_KEY joinKey) {
        this.lostCallback.accept(data, joinKey);
    }

    private BiConsumer<SOURCE_DATA, JOIN_KEY> getDefaultLostFunction() {
        return (data, joinKey) -> {
            log.warn("failed to find join data by {} for {}", joinKey, data);
        };
    }

    @Override
    public int runOnLevel() {
        return this.runLevel;
    }

    @Override
    public String toString() {
        return "JoinExecutorAdapter-for-" + name;
    }
}

参考文章