Spring AOP 切面按照一定规则切片并行查询Mapper并返回

需求:

        有时候我们在查询mapper层时,有时候可能由于入参数据过大或者查询的范围较大,导致查询性能较慢,此时 我们需要将原本的查询按照一定规则将查询范围进行切面,然后分片查询,最后将查询结果进行组装合并

1,自定义注解


import com.taia.yms.aop.reponse.inter.MapperRequestSlicesInterface;
import java.lang.annotation.*;

/**
 * 主要针对 查询 mapper 时,使用一定规则进行切片后,按照指定并发个数进行mapper查询,然后再汇总结果
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MapperRequestSlices {
    /**
     * 指定执行规则的方法,默认方法为:asyncExecute
     * @return
     */
    String method() default "asyncRequestExecute";
    Class<? extends MapperRequestSlicesInterface> operation();
}

2,定义切片规则接口


/**
 * 主要针对mapper层查询,需要按照自定义规则 进行分片并发查询,提升效率
 * @param <T>
 */
public interface MapperRequestSlicesInterface<R,T> {

    R asyncRequestExecute(Object request);

}

3,编写核心切面处理类


import com.taia.yms.aop.reponse.inter.MapperRequestSlicesInterface;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Aspect
@Slf4j
public class MapperRequestSlicesAspect {

    @Pointcut("execution(* com.taia.yms.mapper.*.*(..)) && @annotation(com.taia.yms.aop.reponse.MapperRequestSlices)")
    private void pointCut() {
        //方法为空,仅做签名
    }

    //对切点方法进行前置增强,就是在调用切点方法前进行做一些必要的操作,这就成为增强
    @Around("pointCut()")
    public Object getRes(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取被拦截的方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取被拦截的方法
        Method method = signature.getMethod();
        Object[] objects = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        Class<?> returnType = method.getReturnType();
        //针对 返回值是集合的场景,便于后期切片后汇总
        if(!returnType.getTypeName().equalsIgnoreCase(List.class.getTypeName())){
            return joinPoint.proceed();
        }
        MapperRequestSlices annotation = method.getAnnotation(MapperRequestSlices.class);
        // 查找并获取注解
        try{
            // 读取注解的属性
            Class<? extends MapperRequestSlicesInterface> operation = annotation.operation();
            MapperRequestSlicesInterface operationInstance = operation.getDeclaredConstructor().newInstance();
            String methoded = annotation.method();
            Method operationMethod = operation.getDeclaredMethod(methoded, Object.class);
            Object obj = operationMethod.invoke(operationInstance, objects);
            //如果切分的结果只有一个,那么还是按照原有的查询来
            if(!(obj instanceof List && obj != null)){
                return joinPoint.proceed();
            }
            List<Object> result =((List<?>) obj).stream().flatMap(v -> {
                try {
                    return ((List<Object>)(method.invoke(target, v))).stream();
                } catch (Exception e) {
                    log.error("类[{}]的方法[{}]执行失败,报错:{}",target.getClass().getName(),method.getName(),e.getMessage());
                    throw new RuntimeException(e);
                }
            }).collect(Collectors.toList());
            return result;
        }catch (Throwable e){
            log.error("类[{}]的方法[{}]执行失败,报错:{}",annotation.operation().getName(),annotation.method(),e.getMessage());
            return joinPoint.proceed();
        }
    }


}

4,编写切片规则实现类


import com.taia.yms.aop.reponse.inter.MapperRequestSlicesInterface;
import com.taia.yms.entity.po.QualityViewPo;
import com.taia.yms.entity.requestbody.SummarySearchRequestBody;
import com.taia.yms.entity.vo.DataTypeSlice;
import com.taia.yms.entity.vo.DataTypeVo;
import com.taia.yms.enums.RangeTypeEnum;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import java.util.List;
import java.util.stream.Collectors;

public class DataByTime2ReqSlice implements MapperRequestSlicesInterface<List<SummarySearchRequestBody>,List<QualityViewPo>> {

    @Override
    public List<SummarySearchRequestBody> asyncRequestExecute(Object request) {
        if(request == null){
            return null;
        }
        SummarySearchRequestBody requestBody = (SummarySearchRequestBody) request;
        //按 天统计不考虑
        if(RangeTypeEnum.DAY.getType().equalsIgnoreCase(requestBody.getRangeType())){
            return null;
        }
        DataTypeVo dataTypeVo = requestBody.getDataTypeVo();
        if(dataTypeVo == null || CollectionUtils.isEmpty(dataTypeVo.getDataTypeSliceList())){
            return null;
        }
        List<DataTypeSlice> dataTypeSliceList = dataTypeVo.getDataTypeSliceList();
        dataTypeSliceList.stream().sorted();
        List<SummarySearchRequestBody> bodyList = dataTypeSliceList.stream().map(v -> {
            SummarySearchRequestBody summarySearchRequestBody = new SummarySearchRequestBody();
            BeanUtils.copyProperties(requestBody, summarySearchRequestBody);
            summarySearchRequestBody.setStartDate(v.getStartTime());
            summarySearchRequestBody.setEndDate(v.getEndTime());
            return summarySearchRequestBody;
        }).collect(Collectors.toList());
        return bodyList;
    }

}

5,编写相关对象类


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @ClassName QualityViewPo
 * Date 2023/4/25 11:47
 * Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class QualityViewPo {
    private Integer countNum;
    private String dateTime;
    private Integer successFilesNum;
    private Integer failFilesNum;
    private Integer loadingFilesNum;
    private Integer qualityScore;

    private String fabProductVersion;
    private String station;
}

import com.taia.yms.entity.ExportPageReqBody;
import com.taia.yms.entity.vo.DataTypeVo;
import com.taia.yms.validgroups.summarysearch.DataProgressSummaryGroup;
import com.taia.yms.validgroups.summarysearch.TodayBoardGroup;
import com.taia.yms.validgroups.summarysearch.TrendsBoardGroup;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.sql.Timestamp;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class SummarySearchRequestBody extends ExportPageReqBody {
    /**时间区间 day/week/month*/
    @Valid
    @NotEmpty(message = "时间范围为空", groups = {DataProgressSummaryGroup.class, TrendsBoardGroup.class})
    @Pattern(regexp = "day|week|month|custom|year|all",message = "时间范围不符合正则", groups = {DataProgressSummaryGroup.class, TrendsBoardGroup.class})
    private String rangeType;
    /**开始时间*/
    @NotNull(message = "开始时间为空", groups = {DataProgressSummaryGroup.class, TrendsBoardGroup.class})
    private Timestamp startDate;
    /**结束时间*/
    @NotNull(message = "结束时间为空", groups = {DataProgressSummaryGroup.class, TrendsBoardGroup.class})
    private Timestamp endDate;
    /**数据类型 WAT/INLINE/CP-BIN/DEFECT*/
    @Valid
    @NotNull(message = "数据类型为空", groups = {DataProgressSummaryGroup.class, TodayBoardGroup.class, TrendsBoardGroup.class})
    private List<@NotEmpty(message = "数据类型为空", groups = {DataProgressSummaryGroup.class, TodayBoardGroup.class, TrendsBoardGroup.class}) String> stations;
    /**产品数据 */
    //@NotNull(message = "产品数据为空", groups = {DataProgressSummaryGroup.class, TodayBoardGroup.class, TrendsBoardGroup.class})
    private List<String> fabProductVersions;

    private DataTypeVo dataTypeVo;
}

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;

/**
 * @ClassName ExportPageReqBody
 * 导出 和 分页数据
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ExportPageReqBody {
    /**页码*/
    @ApiModelProperty(example = "1")
    private Integer pageNum = 1;
    /**页面大小*/
    @ApiModelProperty(example = "10")
    private Integer pageSize = 10;

    /**1-导出excel, 0-导出CSV*/
    private String isExcel;
    /**1-只导出表头,0或空-导出表头和数据*/
    private String isEmpty;
    /**1-配置数据, 0或空-待添加配置数据*/
    private String isConfig;
    /**选择导出,有值时只导出选中的id*/
    private List<Long> selectedIds;
    /**当前登录用户的userId*/
    private String userNo;
}

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class DataTypeVo {
    private List<String> timeTable;
    private List<DataTypeSlice> dataTypeSliceList;

}

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.sql.Timestamp;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class DataTypeSlice {
    private Timestamp startTime;
    private Timestamp endTime;
}

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远方的、远方的、、、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值