研发规范第九讲:通用类命名规范(重点)

news2024/11/16 9:20:46

研发规范第九讲:通用类命名规范(重点)

无规范不成方圆。我自己非常注重搭建项目结构的起步过程,应用命名规范、模块的划分、目录(包)的命名,我觉得非常重要,如果做的足够好,别人导入项目后可能只需要10分钟就可以大概了解系统结构。具体规范包括包命名、类的命名、接口命名、方法命名、变量命名、常量命名。本文是研发规范第九讲,通用类命名规范

文章目录

  • 研发规范第九讲:通用类命名规范(重点)
    • 1、管理类命名
      • 1.1、BootStrap,Starter
      • 1.2、Processor
      • 1.3、Manager
      • 1.4、Holder
      • 1.5、Factory
      • 1.6、Provider
      • 1.7、Registrar
      • 1.8、Engine
      • 1.9、Service
      • 1.10、Task
    • 2、传播类
      • 2.1、Context
      • 2.2、Propagator
    • 3、回调类
      • 3.1、Handler,Callback,Trigger,Listener
      • 3.2、Aware
    • 4、监控类
      • 4.1、Metric
      • 4.2、Estimator
      • 4.3、Accumulator
      • 4.4、Tracker
    • 5、内存管理类
      • 5.1、Allocator
      • 5.2、Chunk
      • 5.3、Arena
      • 5.4、Pool
    • 6、过滤检测类
      • 6.1、Pipeline,Chain
      • 6.2、Filter
      • 6.3、Interceptor
      • 6.4、Evaluator
      • 6.5、Detector
    • 7、结构类
      • 7.1、Cache
      • 7.2、Buffer
      • 7.3、Composite
      • 7.4、Wrapper
      • 7.5、Option, Param, Attribute
      • 7.6、Tuple
      • 7.7、Aggreatore
      • 7.8、Iterator
      • 7.9、Batch
      • 7.10、Limiter
    • 8、常见设计模式命名
      • 8.1、Strategy 策略模式
      • 8.2、Adapter 适配器模式
      • 8.3、Action, Command 命令模式
      • 8.4、Event 观察者模式
      • 8.5、Delegate 委托模式
      • 8.6、Builder 建造者模式
      • 8.7、Template 模版设计模式
      • 8.8、Proxy 代理模式
    • 9、解析类命名
      • 9.1、Converter,Resolver
      • 9.2、Parser
      • 9.3、Customizer
      • 9.4、Formatter
    • 10、网络类
      • 10.1、Packet
      • 10.2、Protocol
      • 10.3、Encoder、Decoder、Codec
      • 10.4、Request,Response
    • 11、其它
      • 11.1、Util,Helper
      • 11.2、Mode,Type
      • 11.3、Invoker,Invocation
      • 11.4、Initializer
      • 11.5、Feture,Promise
      • 11.6、Selector
      • 11.7、Reporter
      • 11.8、Constants
      • 11.9、Accessor
      • 11.10、Generator

1、管理类命名

写代码,少不了对统一资源的管理,清晰的启动过程可以有效地组织代码。为了让程序运行起来,少不了各种资源的注册、调度,少不了公共集合资源的管理。

1.1、BootStrap,Starter

一般作为程序启动器使用,或者作为启动器的基类。通俗来说,可以认为是main函数的入口。

AbstractBootstrap
ServerBootstrap
MacosXApplicationBootstrap
DNSTaskStarter

Demo1:

@Component
public class ExtensionBootstrap implements ApplicationContextAware {

    @Resource
    private ExtensionRegister extensionRegister;

    private ApplicationContext applicationContext;

    @PostConstruct
    public void init() {
        Map<String, Object> extensionBeans = applicationContext.getBeansWithAnnotation(Extension.class);
        extensionBeans.values().forEach(
                extension -> extensionRegister.doRegistration((ExtensionPointI) extension)
        );
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

Demo2:MQ消费者启动

@Slf4j
@Component
public class mqConsumerStarter implements ApplicationRunner {
  	@Autowired(required = false)
    Set<MessageCallback> messageCallbackSet;

    @Autowired
    private MQTemplate mqTemplate;
  
  	@Autowired
    private mqAsyncRetryConsumer mqAsyncRetryConsumer;
  	
  	@Override
    public void run(ApplicationArguments args) throws Exception {
        registerAllConsumer();
    }
}

1.2、Processor

某一类功能的处理器,用来表示某个处理过程,是一系列代码片段的集合。

CompoundProcessor
BinaryComparisonProcessor

Demo:车队订单处理器

@Slf4j
@Component
public class ConveyOrderProcessor {
   	@RpcConsumer
    private ConvoyOrderQueryHService convoyOrderQueryHService;

    public List<ConvoySubOrderHVO> getOrderInfoVOByUpdateTimeRange(Date startTime, Date endTime) {
        if (ObjectUtils.anyNull(startTime, endTime)) {
            return Lists.newArrayList();
        }
      	...
}

1.3、Manager

对有生命状态的对象进行管理,通常作为某一类资源的管理入口。

AccountManager
DevicePolicyManager
TransactionManager

Demo:巡检生命周期管理

public interface InspectionManager<T> {
    /**
     * 获取业务类型
     */
    String bizType();

    /**
     * 初始化执行日期
     * @param context 上下文
     */
    void initBatchId(BizContext<T> context);

    /**
     * 执行器标识
     */
    String getExecutorKey();

    /**
     * 执行器执行标识
     */
    String getProcessingKey();

    /**
     * 执行器是否正在执行
     */
    boolean isProcessing();

    /**
     * 设置执行器状态
     *
     * @param status 状态
     */
    void setStatus(ExecutorStatusEnum status);

    /**
     * 获取当前执行器状态
     */
    String getCurrentStatus();
}

1.4、Holder

表示持有某个或者某类对象的引用,并可以对其进行统一管理多见于不好回收的内存统一处理,或者一些全局集合容器的缓存

QueryHolder
InstructionHolder
ViewHolder

Demo:简单缓存-单例

public class SimpleCache {

    private SimpleCache() {
        //do-nothing
    }

    public static FIFOCache<String, Object> getInstance() {
        return SimpleCacheHolder.instance;
    }

    private static class SimpleCacheHolder {
        // 先入先出,一旦缓存满了,先放进去的,先被清空
        private static final FIFOCache<String, Object> instance = CacheUtil.newFIFOCache(100);
    }
}

1.5、Factory

工厂模式,表示此类为工厂类

SessionFactory
ScriptFactory
LiveCaptureFactory

Demo:商品操作工厂

public class ItemOptFactory {

    private Map<String, ItemOptHandler> beanFactory;

    public ItemOptFactory(@Autowired Map<String,ItemOptHandler> beanFactory) {
        this.beanFactory = beanFactory;
    }

    public ItemOptHandler getInstance(ItemOperateSceneEnum operateSceneEnum){
        ItemOptHandler itemOptFactory = beanFactory.get(operateSceneEnum.getBeanName());
        if (Objects.isNull(itemOptFactory)) {
            return null;
        }
        return itemOptFactory;
    }

    public Response<Boolean> commonBiz(Integer fixMethod, List<Long> bizIds) {
        if (Objects.isNull(fixMethod)
                || !FixSkuImageMethod.STABLE_ITEM_ID.getCode().equals(fixMethod)
                || !FixSkuImageMethod.FLEXIBLE_ITEM_ID.getCode().equals(fixMethod)) {
            Response.fail("请选择数据订正方式,1、磐石调用业务id  2、读取文本中固定业务id");
        }
        if (FixSkuImageMethod.FLEXIBLE_ITEM_ID.getCode().equals(fixMethod) && CollectionUtils.isEmpty(bizIds)) {
            Response.fail("缺少业务id,请输入业务id");
        }
        return Response.ok();
    }
}

1.6、Provider

Provider = Strategy + Factory Method。它更高级一些,把策略模式和方法工厂揉在了一块,让人用起来很顺手。Provider 一般是接口或者抽象类,以便能完成子实现

AccountFeatureProvider
ApplicationFeatureProvider
CollatorPorvider

Demo:平台商品扫描接口

@Component
@Slf4j
public class OptItemScanProvider {

    @Autowired
    private MQTemplate mqTemplate;

    // 用于SPU待扫描数据发送
    public void sendMsg(PlatformItemSearchDto platformItemSearchDto) throws MQException {
        String message = ImJsonUtils.objToJson(platformItemSearchDto);
        MQResponse mqResponse = mqTemplate.sendOrderMsg(MqConfigContant.CATEGORY_SCAN_TOPIC, MqConfigContant.OPT_ITEM_CATEGORY_SCAN_TAG, null, message, getCodeKey(platformItemSearchDto));
        if (!mqResponse.isSuccess()) {
            throw new ServiceException("【标准化类目扫描】平台商品待扫描下发MQ失败");
        }
        log.info("【发送消息结束, topic:{}, response:{},message:{},tag:{}", MqConfigContant.CATEGORY_SCAN_TOPIC, mqResponse, message, MqConfigContant.OPT_ITEM_CATEGORY_SCAN_TAG);
    }
}

1.7、Registrar

注册并管理一系列资源

ImportServiceRegistrar
IKryoRegistrar
PipelineOptionRegistrar

Demo:分布式事务注册器

@Configuration
public class DistributedTransactionRegistrar {

    @Bean
    public DistributedTransactionPolicyProperties distributedTransactionPolicyProperties(){
        return new DistributedTransactionPolicyProperties();
    }

    @Bean
    public DistributedTransactionDao distributedTransactionDao(){
        return new DistributedTransactionDao();
    }

    @Bean
    public DistributedTransactionAspect distributedTransactionAspect(){
        return new DistributedTransactionAspect();
    }
}

1.8、Engine

一般是核心模块,用来处理一类功能。引擎是个非常高级的名词,一般的类是没资格用它的

ScriptEngine
DataQLScriptEngine
C2DEngine

Demo1:审核流引擎,主要用于节点的获取,抽象类。

public interface AuditEngine {

    /**
     * 对当前审核节点的相关处理人的关联处理,由具体业务实现,
     *
     * @param appId 当前审核数据
     */
     void callback(Long appId);

    /**
     * 审核成功业务
     *
     * @param appId 当前审核数据
     */
     void success(Long appId, AuditEngineContext auditEngineContext);

    /**
     * 审核失败业务
     *
     * @param appId 当前审核数据
     */
     void fail(Long appId);

    /**
     * 撤回
     * @param appId 当前审核数据
     */
     void revoke(Long appId);
}

在这里插入图片描述

Demo2:状态机发送事件接口

public interface IFsmEngine<E extends Enum<?>, S extends Enum<?>, C extends IFsmContext<E, S>, F extends Enum<?> & IFsmField, PT extends Enum<?>> {

    /**
     * 引擎初始化
     *
     * @param processorRegisters
     * @param pluginRegisters
     */
    void initEngine(Collection<ProcessorRegister<E, S, C, F>> processorRegisters,
                    Collection<PluginRegister<E, S, C, F, PT>> pluginRegisters);

    /**
     * 发送事件
     *
     * @param event
     * @return
     * @throws Exception
     */
    FsmResult sendEvent(AbstractEvent<E> event);
}

1.9、Service

某个服务。

IntegratorServiceImpl
ISelectionService
PersistenceService

Demo:引入货代财务订单服务

@Slf4j
@Component
public class AgentFinanceOrderInspectionService {
  
}

1.10、Task

某个任务。通常是个Runnable

WorkflowTask
FutureTask
ForkJoinTask

Demo:延时任务

@Getter
@Setter
public abstract class AbstractDelayedTask implements Delayed, Runnable {
    protected final static long DELAY = 10 * 1000L;
    private long updateTime;
    private long objectId;

    @Override
    public void run() {
        process();
    }

    protected abstract boolean process();

    @Override
    public long getDelay(TimeUnit unit) {
        return 0;
    }

    @Override
    public int compareTo(Delayed o) {
        return 0;
    }
}

2、传播类

为了完成一些统计类或者全局类的功能,有些参数需要一传到底。传播类的对象就可以通过统一封装的方式进行传递,并在合适的地方进行拷贝或者更新。

2.1、Context

如果你的程序执行,有一些变量,需要从函数执行的入口开始,一直传到大量子函数执行完毕之后。这些变量或者集合,如果以参数的形式传递,将会让代码变得冗长无比。这个时候,你就可以把变量统一塞到Context里面,以单个对象的形式进行传递

在Java中,由于ThreadLocal的存在,Context甚至可以不用在参数之间进行传递

AppContext
ServletContext
ApplicationContext

Demo:业务上下文

@Data
@Accessors(chain = true)
public class BizContext<T> {

    /**
     * 批次id
     */
    public Long batchId;

    /**
     * 业务最新更新时间
     */
    private long bizLastSyncTime;

    /**
     * 上游业务
     */
    private List<T> upstreamBizList;

    /**
     * 下游业务
     */
    private List<T> downstreamBizList;

    /**
     * 巡检结果
     */
    private List<T> checkResultList;
}

2.2、Propagator

传播,繁殖。用来将context中传递的值进行复制,添加,清除,重置,检索,恢复等动作。通常,它会提供一个叫做propagate的方法,实现真正的变量管理。

TextMapPropagator
FilePropagator
TransactionPropagator

3、回调类

使用多核可以增加程序运行的效率,不可避免的引入异步化。我们需要有一定的手段,获取异步任务执行的结果,对任务执行过程中的关键点进行检查。回调类API可以通过监听、通知等形式,获取这些事件。

3.1、Handler,Callback,Trigger,Listener

callback通常是一个接口,用于响应某类消息,进行后续处理;

Handler通常表示持有真正消息处理逻辑的对象,它是有状态的;

trigger 触发器代表某类事件的处理,属于Handler,通常不会出现在类的命名中;

Listener的应用更加局限,通常在观察者模式中用来表示特定的含义。

ChannelHandler
SuccessCallback
CronTrigger
EventListener

CallBack Demo:批量调度子任务

public abstract class AbstractConsumerChildrenCallBack implements MessageCallback, ApplicationRunner {
  	@Autowired
    private BatchJobWriteFacade batchJobWriteFacade;
    @Autowired
    private mqConsumerManager consumerManager;

    public void init() throws MQException {
        Map<String, MessageCallback> map = Maps.newHashMap();
        map.put(getConsumerId(), ImConsumerEnhanceUtil.enhanceAll(getConsumerId(), this));
        consumerManager.listenMessage(map);
    }
  
  	@Override
    public void run(ApplicationArguments args) throws Exception {
        init();
    }

    @Override
    public MQConsumeStatus messageArrived(MQMessage mqMessage) {
      	...
    }
}

Handler Demo: 协议变更联动商品变更

public interface BizChangeHandler {

    /**
     * 联动商品状态
     * @param agItems 协议商品
     * @param bizChangeContext 业务变更上下文
     * @return 联动的结果
     */
    Object associateItemChangeV1(List<Item> agItems, BizChangeContext bizChangeContext);
}

Listener Demo:商品更新事件监听

@Slf4j
@Component
public class GoodsUpdateListener {
  	 /**
     * 商品更新扩展操作
     * 1. 记录涨价免审日志
     */
    @Async("asyncApplicationEventThreadPool")
    @EventListener
    public void onGoodsUpdate(GoodsSkuUpdateEvent event) {
      	...
    }
}

3.2、Aware

Aware就是感知的意思,一般以该单词结尾的类,都实现了Aware接口。拿Spring来说,Aware 的目的是为了让bean获取Spring容器的服务。具体回调方法由子类实现,比如ApplicationContextAware。它有点回调的意思。

ApplicationContextAware
ApplicationStartupAware
ApplicationEventPublisherAware

Demo:对mq进行trace增强

@Configuration
@Slf4j
public class CommonMqConfig implements ApplicationRunner, ApplicationContextAware {
  	@Autowired
    private mqConsumerManager consumerManager;

    private ApplicationContext applicationContext;
  
  	@Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("[MQ 启动消费者加载]");
        Map<String, Object> consumerMap = applicationContext.getBeansWithAnnotation(mqConsumer.class);
        Map<String, MessageCallback> callbackMap = Maps.newHashMap();
        consumerMap.forEach((beanName, callback) -> {
            try {
                mqConsumer consumer = callback.getClass().getAnnotation(mqConsumer.class);
                if (Objects.nonNull(consumer)) {
                    callbackMap.put(consumer.id(), (MessageCallback) callback);
                }
            } catch (Exception e) {
                log.error("[MQ 启动消费者加载失败], cid: {}, callback: {}", beanName, callback, e);
                throw e;
            }
        });
        log.info("[MQ 启动消费者加载成功]消费者集合为:{}", callbackMap);

        // 为消费方设置好callback 并启动消费方
        try {
            log.info("[MQ 启动消费者监听配置]");
            consumerManager.listenMessage(callbackMap);
            log.info("[MQ 启动消费者监听配置成功]");
        } catch (MQException e) {
            log.error("[MQ 注册监听器失败], map:{}", callbackMap, e);
            throw e;
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

4、监控类

现在的程序都比较复杂,运行状态监控已经成为居家必备之良品。监控数据的收集往往需要侵入到程序的边边角角,如何有效的与正常业务进行区分,是非常有必要的。

4.1、Metric

表示监控数据。不要用Monitor了,比较丑。

TimelineMetric
HistogramMetric
Metric

4.2、Estimator

估计,统计。用于计算某一类统计数值的计算器。

ConditionalDensityEstimator
FixedFrameRateEstimator
NestableLoadProfileEstimator
DefaultMessageSizeEstimator // nacos 客户端

4.3、Accumulator

累加器的意思。用来缓存累加的中间计算结果,并提供读取通道。

AbstractAccumulator
StatsAccumulator
TopFrequencyAccumulator

4.4、Tracker

一般用于记录日志或者监控值,通常用于apm中

VelocityTracker
RocketTracker
MediaTracker

5、内存管理类

如果你的应用用到了自定义的内存管理,那么下面这些名词是绕不开的。比如Netty、lucene,就实现了自己的内存管理机制。

5.1、Allocator

与存储相关,通常表示内存分配器或者管理器。如果你的程序需要申请有规律的大块内存,allocator是你得不二选择。

AbstractByteBufAllocator
ArrayAllocator
RecyclingIntBlockAllocator

5.2、Chunk

表示一块内存。如果你想要对一类存储资源进行抽象,并统一管理,可以采用它。

EncryptedChunk
ChunkFactory
MultiChunk

5.3、Arena

英文是舞台、竞技场的意思。由于Linux把它用在内存管理上发扬光大,它普遍用于各种存储资源的申请、释放与管理。为不同规格的存储chunk提供舞台,好像也是非常形象的表示。

关键是,这个词很美,作为后缀让类名显得很漂亮。

BookingArena
StandaloneArena
PoolArena

5.4、Pool

表示池子。内存池,线程池,连接池,池池可用。

ConnectionPool
ObjectPool
MemoryPool

Demo:线程池

public class EventBusThreadPool extends ThreadPoolExecutor {
  	/**
     * 默认线程大小
     */
    private static final int DEFAULT_THREAD_SIZE = Runtime.getRuntime().availableProcessors();

    private static final AtomicInteger threadNum = new AtomicInteger(1);

    /**
     * 线程池名称
     */
    private static final String NAME = "EventBusThreadPool";

    /**
     * 线程池实例
     */
    public static EventBusThreadPool pool = new EventBusThreadPool();

    private EventBusThreadPool() {
        super(DEFAULT_THREAD_SIZE, DEFAULT_THREAD_SIZE, 0,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(20000),
                r -> new Thread(r, NAME + "-" + threadNum.getAndDecrement()),
                new EventBusThreadPool.RewriteCallerRunsPolicy());
    }

    @Override
    public void execute(Runnable command) {
        String traceId = TraceIdUtil.getCurrentTraceId();
        try {
            // traceId显示传入
            super.execute(() -> {
                TraceIdUtil.initTraceId(traceId);
                try {
                    command.run();
                } finally {
                    TraceIdUtil.clearTraceId();
                }
            });
        } catch (Exception e) {
            log.error("[EventBusThreadPool-execute-error], traceId:{}", traceId, e);
            super.execute(command);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        String traceId = TraceIdUtil.getCurrentTraceId();
        try {
            // traceId显示传入
            return super.submit(() -> {
                TraceIdUtil.initTraceId(traceId);
                try {
                    task.run();
                } finally {
                    TraceIdUtil.clearTraceId();
                }
            });
        } catch (Exception e) {
            log.error("[EventBusThreadPool-submit-error], traceId:{}, cause:", traceId, e);
            return super.submit(task);
        }
    }

    /**
     * 线程池已经无法处理,重写饱和策略,跟CallerRunsPolicy一样,超出后需要调用者自己的线程处理,多了记录日志
     */
    private static class RewriteCallerRunsPolicy implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            log.error("线程池:{} 需要处理的任务已经超过任务队列长度(当前队列长度:{}), 需要当前的工作线程自行处理当前任务", NAME, executor.getQueue().size());
            if (!executor.isShutdown()) {
                r.run();
            }
        }
    } 
}

6、过滤检测类

程序收到的事件和信息是非常多的,有些是合法的,有些需要过滤扔掉。根据不同的使用范围和功能性差别,过滤操作也有多种形式。你会在框架类代码中发现大量这样的名词。

6.1、Pipeline,Chain

一般用在职责链设计模式中。Netty,Spring MVC,Tomcat等都有大量应用。通过将某个处理过程加入到职责链的某个位置中,就可以接收前面处理过程的结果,强制添加或者改变某些功能。就像Linux的管道操作一样,最终构造出想要的结果。

  • 职责链设计模式可以参考这篇文章:JAVA设计模式第四讲:行为型设计模式
    • 第10.4节
Pipeline
ChildPipeline
DefaultResourceTransformerChain
FilterChain

Demo1:规则执行器注册中心

@Component
class RuleExecutorPipeline {

    private final List<RuleExecutor> ruleExecutors = new ArrayList<>();

    public List<RuleExecutor> getRuleExecutors() {
        return ruleExecutors;
    }

    /**
     * 清空所有的规则
     */
    public void clear(){
        ruleExecutors.clear();
    }

    /**
     * 批量添加规则
     *
     * @param ruleExecutors   待添加的规则
     */
    protected void addAll(List<RuleExecutor> ruleExecutors){
        ruleExecutors.addAll(ruleExecutors);
    }

    /**
     * 单个添加规则
     *
     * @param ruleExecutor 待添加的规则
     */
    protected void add(RuleExecutor ruleExecutor){
        ruleExecutors.add(ruleExecutor);
    }
}

Demo2:职责链设计模式

public class RuleChain {
  	@Override
    public void configureRuleExecutors(GeneralRuleExecutorRegistry ruleExecutorRegistry) {
        /** 业务规则校验逻辑 */
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.BUSINESS_EXCEUTOR,new BusinessExceutor());
        /** 基本规则校验(必填等) */
        //平台级基本校验规则
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.BASE_EXCEUTOR,new BaseExceutor(shopSyncAgent, backCategorySyncAgent, stockReadService,
                itemReadService, addressSyncAgent, categoryAttributeSyncAgent,instanceConfigAgent));
        //平台禁售规则校验
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.FORBID_SALE_EXCEUTOR,new ForbidSaleExceutor());
        //敏感词规则校验
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.SENSITIVE_WORD_EXCEUTOR,new SensitiveWordExceutor(sensitiveWordSyncAgent));

        /** 唯一性校验 */
        //itemCode, skuCode
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.UNIQUE_CODE_EXCEUTOR,new UniqueCodeExceutor(shopSyncAgent, itemReadService, skuReadService));
        //给input对象附上keyAttrs, boundAttrs, backCategory的信息
       	ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.OTHER_ATTRIBUTE_FILTER_BY_CATEGORY_EXECUTOR,new OtherAttributeFilterByCategoryExecutor(categoryAttributeSyncAgent,
                backCategorySyncAgent));
        // 商品关键属性校验器(同店铺下,同关键属性的商品只能发布一个)
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.UNIQUE_KEY_ATTRS_EXCEUTOR,new UniqueKeyAttrsExceutor(categoryAttributeSyncAgent, itemReadService, configComponent,itemAttributeReadService, keyAttrAllowChangeWhiteListConfiguration,spuSyncAgent,brandReadService));
        //标准类目下的item的input,直接注入对应SPU的管控的属性值
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.ITEM_OTHER_ATTRIBUTE_INPUT_RULE_BY_ALI_SPU_EXECUTOR,new ItemOtherAttributeInputRuleByAliSpuExecutor(categoryAttributeSyncAgent, backCategorySyncAgent, spuSyncAgent,shopSyncAgent));

        //标准类目下的item的output,向output的规则里注入spu规则
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.ITEM_OTHER_ATTRIBUTE_OUTPUT_RULE_BY_ALI_SPU_EXECUTOR, new ItemOtherAttributeOutputRuleByAliSpuExecutor(backCategorySyncAgent, spuSyncAgent));
        /** 校验商品的 groupedSkuAttributes */
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.ITEM_SKU_ATTRIBUTE_RULE_BY_CATEGORY_EXECUTOR, new ItemSkuAttributeRuleByCategoryExecutor(categoryAttributeSyncAgent, spuReadServiceFacade, backCategorySyncAgent));
        //spu
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.SPU_OTHER_ATTRIBUTE_RULE_BY_CATEGORY_EXECUTOR, new SpuOtherAttributeRuleByCategoryExecutor(categoryAttributeSyncAgent, outPlatformLinkServiceAgent, addressSyncAgent));
        /** 校验商品的 skus
         * out 方法 -> 如果 属性值域不合规,就会导致对应的skus为空
         */
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.SKU_RULE_BY_CATEGORY_EXECUTOR,new SkuRuleByCategoryExecutor(categoryAttributeSyncAgent));

        // 增加不受管控的属性处理执行器(回填商品主信息,校验 发布商品时 品牌+型号 在同店铺下是否存在)
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.OUT_OF_CONTROL_ATTRIBUTE_EXECUTOR,new OutOfControlAttributeExecutor(brandReadService, itemAttributeReadService));
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.ITEM_OTHER_ATTRIBUTE_RULE_BY_AG_CATEGORYEXECUTOR,new ItemOtherAttributeRuleByAgCategoryExecutor(agCategoryAttributeReadService,
                instanceConfigAgent, zcyCategoryInstanceConfigService));
        // 格式标题
        ruleExecutorRegistry.register(GeneralRuleExecutorRegistry.ITEM_FORMAT_TITLE_EXECUTOR,new ItemFormatTitleExecutor(itemReadService, imCategoryConfigCache, configComponent));
    }
}

6.2、Filter

过滤器,用来筛选某些满足条件的数据集,或者在满足某些条件的时候执行一部分逻辑。如果和职责链连接起来,则通常能够实现多级的过滤。

FilenameFilter
AfterFirstEventTimeFilter
ScanFilter

Demo1:增加dubbo filter

1、需要在resources目录下的META-INF/dubbo/添加com.alibaba.dubbo.rpc.Filter文件
2、然后配置dubboMonitor=cn.gov.zcy.service.filter.DubboCheckMonitorFilter
3、<dubbo:provider filter=“dubboMonitor” />

@Slf4j
@Activate(group = {CommonConstants.PROVIDER})
public class DubboCheckMonitorFilter implements Filter {
  	 @Override
  	 @SuppressWarnings("all")
   	 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        final Boolean isMonitorEnable = ApolloConfigUtil.getBooleanProperty(
                "item.dubbo.monitor.enable", false
        );
        Stopwatch stopwatch = isMonitorEnable ? Stopwatch.createStarted() : null;
        // invoke
        Result result = invoker.invoke(invocation);
        try {
            // consumer 无需拦截,没什么意义
            if (isMonitorEnable && !RpcContext.getContext().isConsumerSide()) {
                handler(stopwatch, result, invocation);
            }
            return result;
        } catch (Exception e) {
            log.error("DubboCheckMonitor发生异常", e);
            return result;
        }
    }
}

Demo2:Spring filter 商品发布前置校验

  • 商品发布前置校验器, 使用filter模式实现, 可以在内进行如: 规则校验, 数据预处理等,添加校验器时需兼容考虑单发和批量发布的场景,单发和批量在大部分场景下的规则一致.
  • 扩展性 1. 允许自定义校验器Filter 2. 允许自定义校验器Manager内部的Filter
public interface PublishPreValidatorFilter {

    /**
     * 执行校验操作
     * @param publishFilterContext
     * @return true, 校验成功. false, 校验失败
     */
    Response<Void> execute(PublishFilterContext publishFilterContext);
}

@Component
public class PublishPreValidatorManager implements InitializingBean {

    @Autowired
    private PublishItemNumPreValidatorFilter publishItemNumPreValidatorFilter;

    private List<PublishPreValidatorFilter> preValidatorFilters = new ArrayList();

    public Response<Void> execute(PublishFilterContext publishFilterContext) {
        if (CollectionUtils.isEmpty(preValidatorFilters)) {
            return Response.ok();
        }

        for (PublishPreValidatorFilter preValidatorFilter : preValidatorFilters) {
            Response<Void> filterResult = preValidatorFilter.execute(publishFilterContext);
            if (!filterResult.isSuccess()) {
                return Response.fail(filterResult.getCode(), filterResult.getMessage());
            }
        }
        return Response.ok();
    }

    private void addFilter(PublishPreValidatorFilter filter){
        preValidatorFilters.add(filter);
    }

    // 默认校验器
    @Override
    public void afterPropertiesSet() throws Exception {
        addFilter(publishItemNumPreValidatorFilter);
    }
}

6.3、Interceptor

拦截器,其实和Filter差不多。不过在Tomcat中,Interceptor可以拿到controller对象,但filter不行。拦截器是被包裹在过滤器中。

HttpRequestInterceptor

Demo1:Mybatis 拦截器

@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MysqlPermissionInterceptor implements Interceptor {
  	@Override
    public Object intercept(Invocation invocation) throws Throwable {
      	// 执行代码增强逻辑
      	...
    }
  	
  	@Override
    public Object plugin(Object target) {
      	
    }
  
  	@Override
    public void setProperties(Properties properties) {

    }
}

Demo2:SpringMVC 防重提交拦截器

@Component
@Slf4j
public class ResubmitCheckInterceptor implements HandlerInterceptor {
  	 @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
       	...
     }
  
  	 @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
      	...
    }  
}

6.4、Evaluator

英文里是评估器的意思。可用于判断某些条件是否成立,一般内部方法 evaluate 会返回bool类型。比如你传递进去一个非常复杂的对象,或者字符串,进行正确与否的判断。

ScriptEvaluator
SubtractionExpressionEvaluator
StreamEvaluator

6.5、Detector

探测器。用来管理一系列探测性事件,并在发生的时候能够进行捕获和响应比如Android的手势检测,温度检测等

FileHandlerReloadingDetector
TransformGestureDetector 
ScaleGestureDetector

7、结构类

除了基本的数据结构,如数组、链表、队列、栈等,其他更高一层的常见抽象类,能够大量减少大家的交流,并能封装常见的变化。

7.1、Cache

这个没啥好说的,就是缓存。大块的缓存。常见的缓存算法有LRU(Redis)、LFU(caffeine cache)、FIFO(HashMap)等。

LoadingCache
EhCacheCache

Demo:分布式缓存

@Slf4j
@Component
public class RedisCache {
  	@Autowired
    private RedisClientManager redisClientManager;
  	
  	/**
     * 获取业务线更新时间
     * @param redisBizType 业务类型
     * @return 最新更新时间
     */
    public long getOrderLastSyncTime(String redisBizType) {
        try {
            String result = redisClientManager.get(redisBizType);
            if (StringUtils.isNotBlank(result )) {
                return Long.parseLong(result);
            }
        } catch (Exception e) {
            log.error("RedisCommonCache.getOrderLastSyncTime err, param:{}", redisBizType, e);
        }
        return System.currentTimeMillis() - 5 * 60 * 1000;
    }
}


// 通用缓存工具类
public abstract class AbstractCommonCache<T> {
  	/**
     * 根据id信息批量从Redis中获取
     * @param paramIds 参数ID
     * @param keyPrefix Redis key前缀
     * @return 缓存结果
     */
  	protected List<T> findBatchCacheByIds(List<Long> paramIds, String keyPrefix, LongAdder hitRequest){
      	...
    }
  
  	 /**
     * 根据id信息从Redis中获取
     * @param paramId 参数ID
     * @param keyPrefix Redis key前缀
     * @return 缓存结果
     */
    protected T findCacheById(Long paramId, String keyPrefix, LongAdder hitRequest) {
      	...
    }
}

Demo2:fifo cache 简单缓存,单例

public class SimpleCache {

    private SimpleCache() {
        //do-nothing
    }

    public static FIFOCache<String, Object> getInstance() {
        return SimpleCacheHolder.instance;
    }

    private static class SimpleCacheHolder {
        // 先入先出,一旦缓存满了,先放进去的,先被清空
        private static final FIFOCache<String, Object> instance = CacheUtil.newFIFOCache(100);
    }
}

7.2、Buffer

buffer是缓冲,不同于缓存,它一般用在数据写入阶段。

ByteBuffer
RingBuffer
DirectByteBuffer

7.3、Composite

将相似的组件进行组合,并以相同的接口或者功能进行暴露,使用者不知道这到底是一个组合体还是其他个体。

CompositeData
CompositeMap
ScrolledComposite

Demo:组合属性

@Data
public class PropertyComposite implements Serializable{

    /**
     * 属性
     */
    private Property property;

    /**
     * 所组合的属性
     */
    private List<Property> composites;
}

7.4、Wrapper

用来包装某个对象,做一些额外的处理,以便增加或者去掉某些功能

IsoBufferWrapper
ResponseWrapper
MavenWrapperDownloader 

Demo:对page类增强

@Getter
@Setter
public class PageParamWrapper extends PageParam {

    /**
     * 排序方式,asc:正序,desc:倒序(默认)
     */
    private String orderType = "desc";

    /**
     * 排序字段
     */
    private String orderField;
}

7.5、Option, Param, Attribute

用来表示配置信息。说实话,它和Properties的区别并不大,但由于Option通常是一个类,所以功能可以扩展的更强大一些。它通常比Config的级别更小,关注的也是单个属性的值。Param一般是作为参数存在,对象生成的速度要快一些。

SpecificationOption
SelectOption
AlarmParam
ModelParam

Demo:param使用场景,作为接口的入参

@Data
@Accessors(chain = true)
public class SlowSqlCreateParam {
  	...
}

7.6、Tuple

元组的概念。由于Java中缺乏元组结构,我们通常会自定义这样的类。

Tuple2
Tuple3
  • 我们在业务上使用的是Pair这个类

7.7、Aggreatore

聚合器,可以做一些聚合计算。比如分库分表中的sum,max,min等聚合函数的汇集。

BigDecimalMaxAggregator
PipelineAggregator
TotalAggregator
  • 使用较少

7.8、Iterator

迭代器。可以实现Java的迭代器接口,也可以有自己的迭代方式。在数据集很大的时候,需要进行深度遍历,迭代器可以说是必备的。使用迭代器还可以在迭代过程中安全的删除某些元素

BreakIterator
StringCharacterIterator

可以参考这篇文章:JAVA设计模式第四讲:行为型设计模式

  • 第10.6节

7.9、Batch

某些可以批量执行的请求或者对象。

SavedObjectBatch
BatchRequest

Demo:批量任务

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BatchJobDetailDto implements Serializable {
   	...
}

7.10、Limiter

限流器,使用漏桶算法或者令牌桶(Ratelimiter)来完成平滑的限流。

DefaultTimepointLimiter
RateLimiter
TimeBasedLimiter

Demo1:Ratelimiter 分时段限流

@Slf4j
public class TimeRateLimiter implements RateLimiter {

    public static final String PREFIX = "time.rate.limiter.";

    private String name;

    private String key;

    volatile TimeRateLimiterConfig limiterConfig;

    /**
     * 限流-时段
     */
    com.google.common.util.concurrent.RateLimiter timeRateLimiter = null;

    /**
     * 限流-默认
     */
    com.google.common.util.concurrent.RateLimiter defaultRateLimiter = null;

    public TimeRateLimiter(String name) {
        if (!StringUtils.hasText(name)) {
            log.error("RateLimiter, the TimeRateLimiter name is invalid");
            throw new IllegalArgumentException("the TimeRateLimiter name is invalid");
        }
        this.name = name;
        this.key = buildKey(this.name);
        this.init();

    }

    private void init() {
        refresh();
        Config config = ConfigService.getAppConfig();
        config.addChangeListener(e -> TimeRateLimiter.this.refresh(), Sets.newHashSet(key));
    }
  
  	/**
     * 限流
     */
    @Override
    public void acquire(int permits) {
      	...
    }
}

Demo2:商品发布频率限制

@Slf4j
@Component
public class ItemFrequencyLimiter implements ItemRiskControlLimiter {
  	@Override
    public Boolean preLimit(String apolloRuleKey, LoginUser loginUser) {
      
    }
  
  	@Override
    public void postProcess(String apolloRuleKey, LoginUser loginUser) {
        // 异步执行规则校验
        asyncExecutor(apolloRuleKey, loginUser);
    }
}

8、常见设计模式命名

8.1、Strategy 策略模式

将抽象部分与它的实现部分分离,使它们都可以独立地变化。策略模式。相同接口,不同实现类,同一方法结果不同,实现策略不同。比如一个配置文件,是放在xml里,还是放在json文件里,都可以使用不同的provider去命名。

RemoteAddressStrategy
StrategyRegistration
AppStrategy

Demo:经营看板模版

public abstract class AbstractDashboardStrategy<T> {
  	 protected abstract T detail(DashboardParam param);
}

public class BusinessOverviewStrategy extends AbstractDashboardStrategy<BusinessOverviewVO> {
  	@Override
    public BusinessOverviewVO detail(DashboardParam param) {
      	...
    }
}

8.2、Adapter 适配器模式

将一个类的接口转换为客户希望的另一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类一起工作

不过,相对于传统的适配器进行api转接,如果你的某个Handler里面方法特别的多,可以使用Adapter实现一些默认的方法进行适配。那么其他类使用的时候,只需要继承Adapter,然后重写他想要重写的方法就可以了。这也是Adapter的常见用法。

ExtendedPropertiesAdapter
ArrayObjectAdapter
CardGridCursorAdapter

Demo:EventBus 适配器,将Event封装到 EventAdapter 对象中

@Slf4j
public abstract class EventAdapter<T extends BaseEvent> {

    /**
     * 抽象监听
     * @param e
     * @return
     */
    public abstract EventResult process(T e);

    /**
     * 启动开关
     * @return
     */
    public abstract boolean enable();

    /**
     * @return
     */
    public Consumer<T> failedHook() {
        return (T t) -> log.warn("handle event {} fail", t.getClass().getName());
    }
    
    @Subscribe
    @AllowConcurrentEvents
    public void onEvent(T event) {
        if (!enable()) {
            return;
        }
        EventResult result = process(event);
        if (!ObjectUtils.isEmpty(result) && !result.getSuccess()) {
            failedHook().accept(event);
        }
    }

    /**
     * 获取泛型的class name
     * @return
     */
    @SuppressWarnings("all")
    public String getRegisterEventName() {
        Class<T> clazz =
            (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return clazz.getName();
    }
}

8.3、Action, Command 命令模式

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作

用来表示一系列动作指令,用来实现命令模式,封装一系列动作或者功能。Action一般用在UI操作上,后端框架可以无差别的使用。

在DDD的概念中,CQRS的Command的C,既为Command。

DeleteAction
BoardCommand

Demo1:命令模式在订单中的使用

public abstract class ClientAction {

    public abstract boolean when(OrderInfo orderInfo, Integer orderState);

    public abstract ServiceResponse<Long> check(OrderInfo orderInfo, Integer orderState);

    public abstract ServiceResponse<Long> then(OrderInfo orderInfo, Long updateUser);

    public Integer order() {
        return Integer.MIN_VALUE;
    }
}

// 流转到已进港规则处理器
@Slf4j
@Service
public class ClientEnterPortAction extends ClientAction {
  	@Autowired
    private OrderFsmEngine orderFsmEngine;
  	
  	@Override
    public boolean when(OrderInfo orderInfo, Integer orderState) {
      	...
    }
  	
  	@Override
    public ServiceResponse<Long> check(OrderInfo orderInfo, Integer orderState) {
      	
    }
  
  	@Override
    public ServiceResponse<Long> then(OrderInfo orderInfo, Long updateUser) {
      	...
    }
  
  	@Override
    public Integer order() {
        return 9;
    }
}

Demo2:命令模式在商品扫描中的应用

public interface ScanAction {
  	/**
     * 抽象执行方法
     *
     * @param scanActionContext 扫描处理上下文
     * @return 是否执行完成
     */
		Response<Boolean> excute(ScanActionContext scanActionContext);

    /**
     * 抽象拉取结果方法,请保证此方法不能为空
     *
     * @param categoryId 类目ID
     * @return 通用结果
     */
    ScanResult getResult(Long categoryId);

    /**
     * 补偿逻辑,用于测试、后门接口补偿任务等,按需实现,没有强制逻辑
     *
     * @param scanActionContext
     * @return
     */
    Boolean compensate(ScanActionContext scanActionContext);
}

// SPU扫描
@Component
@Slf4j
public class SpuScanAction extends AbstractBaseScanAction {
  	@Override
    public Response<Boolean> excute(ScanActionContext scanActionContext) {
        ...
    }
  	@Override
    public ScanResult getResult(Long categoryId) {
      	...
    }
   	@Override
    public Boolean compensate(ScanActionContext scanActionContext) {
      	...
    }
}

8.4、Event 观察者模式

表示一系列事件。一般的,在语义上,Action,Command等,来自于主动触发; Event来自于被动触发。

ObservesProtectedEvent
KeyEvent

Demo:Spring Event 状态机事件

public abstract class AbstractEvent<E extends Enum<?>> {

    /**
     * 状态机锁ID
     */
    private String lockId;

    /**
     * 获取事件类型
     *
     * @return
     */
    public abstract E getEventType();

    /**
     * 获取状态机锁ID
     *
     * @return
     */
    public String getLockId() {
        return lockId;
    }

    /**
     * 设置状态机锁ID
     *
     * @param lockId
     */
    public void setLockId(String lockId) {
        this.lockId = lockId;
    }
}

// 创建订单事件
@Setter
@Getter
public class CreateOrderEvent extends AbstractOrderEvent {

    private OrderInfo orderInfo;

    @Override
    public ConvoyOrderEvent getEventType() {
        return ConvoyOrderEvent.CREATE;
    }
}

8.5、Delegate 委托模式

代理或者委托模式。委托模式是将一件属于委托者做的事情,交给另外一个被委托者来处理。

LayoutlibDelegate
FragmentDelegate

Demo:

@Slf4j
@Service
public class CustomerDoorsDelegateService {

  	@Autowired
    private CustomerDoorsHService customerDoorsHService;
  
  	public Long getDoorsId(OrderInfo orderInfo, DeliveryLoadingInfo deliveryLoadingInfo) {
      	ServiceResponse<Long> response = customerDoorsHService.add(customerDoorsHParam);
      	...
    }
}
  • 我们在项目中对于委托一般命名为 xxxAgent

8.6、Builder 建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

构建者模式的标准命名。比如StringBuilder。当然StringBuffer是个另类。这也说明了,规则是人定的,人也可以破坏。

JsonBuilder
RequestBuilder

Demo:ES使用构造者模式来生成参数

public class EsParamBuilder {
  	 private BoolQueryBuilder queryBuilder;

    public EsParamBuilder() {
        queryBuilder = new BoolQueryBuilder();
    }

    public EsParamBuilder termQuery(String key, Object value) {
      	...
      	return this;
    }
  
  	public EsParamBuilder must(QueryBuilder builder) {
        if (Objects.isNull(builder)) {
            return this;
        }
        queryBuilder.must(builder);
        return this;
    }
  	
		public EsParamBuilder should(QueryBuilder builder) {
        if (Objects.isNull(builder)) {
            return this;
        }
        queryBuilder.should(builder);
        return this;
    }
  
  	public BoolQueryBuilder buildParam() {
        return queryBuilder;
    }
}

8.7、Template 模版设计模式

模板方法类的命名。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

JDBCTemplate

Demo:巡检项目模板类

public abstract class AbstractInspectionTemplate<T> implements InspectionManager<T> {

    @Autowired
    private BizDiffMapper bizDiffMapper;

    // 模版方法
    public final boolean inspectionMethod() {
        Stopwatch stopwatch = Stopwatch.createStarted();
        BizContext<T> context;
        try {
            if (isProcessing()) {
                //任务正在执行中
                log.warn("当前任务正在执行,本次执行忽略: 唯一键{}", getExecutorKey());
                return false;
            }
            context = fillBizData();
            // 获取batchId
            initBatchId(context);
            // 对账处理
            doInspection(context);
        } catch (Exception e) {
            setStatus(ExecutorStatusEnum.ERROR);
            log.warn("获取巡检数据失败, 唯一键{}, 执行器状态为:{},cause:", getExecutorKey(), getCurrentStatus(), e);
            return false;
        }
        // 差错处理
        boolean result = handleMistake(context);
        setStatus(ExecutorStatusEnum.END);
        log.info("巡检任务执行耗时:{}ms, 唯一键{}, 巡检结果:{}", stopwatch.elapsed(TimeUnit.MILLISECONDS), getExecutorKey(), getCurrentStatus());
        return result;
    }
  	
  	/**
     * 数据获取
     * 定时任务按更新时间查询近5s到近5m+5s的数据
     * 先获取上游,拿到ids,然后由ids查询下游业务
     * @return 上下文
     */
    protected abstract BizContext<T> fillBizData() throws SQLException;

    /**
     * 对账处理
     * @param bizContext 上下文
     */
    protected abstract void doInspection(BizContext<T> bizContext);

    /**
     * 对补偿数据异步处理,发送mq,并记录同步时间
     * @param bizContext 上下文
     */
    protected abstract boolean handleMistake(BizContext<T> bizContext);
}

8.8、Proxy 代理模式

代理模式。为其他对象提供一种代理以控制对这个对象的访问。

ProxyFactory 
SlowQueryProxy

Demo:创建商品云岛动态代理

@Component
public class CloudServiceItemWriteApiProxy {

    @Autowired
    private CloudServiceItemWriteApi cloudServiceItemWriteApi;

    public Response<ItemIdDTO> create(ItemCreateCmd createCmd) {

        //岛端创建基础商品,需要将仓库编码置为null
        if(Env.isIsland()){
            createCmd.clearWarehouseCode();
            createCmd.clearTransExpenses();
            Object result = ItemPlatformGeneric.invokeParams(CloudServiceItemWriteApi.class, "create", createCmd);
            return JSONObject.parseObject(JSON.toJSONString(result), new TypeReference<Response<ItemIdDTO>>() {});
        }
        return cloudServiceItemWriteApi.create(createCmd);
    }
}

9、解析类命名

写代码要涉及到大量的字符串解析、日期解析、对象转换等。根据语义和使用场合的区别,它们也分为多种。

9.1、Converter,Resolver

转换和解析。一般用于不同对象之间的格式转换,把一类对象转换成另一类。注意它们语义上的区别,一般特别复杂的转换或者有加载过程的需求,可以使用Resolver

DataSetToListConverter
LayoutCommandLineConverter
InitRefResolver
MustacheViewResolver

Demo:解析用户信息Resolver

@Component
public class UserIdLockKeyResolver implements LockKeyGenerator {

    @Override
    public String resolverLockKey(ResubmitCheck resubmitCheck, HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) {
        AdminServiceParam serviceParam = GatewayContext.getAdminServiceParam();
        Long userId = 0L;
        if (Objects.nonNull(serviceParam)) {
            userId = serviceParam.getUserId();
        }
        return String.format("%s_%s", userId, request.getRequestURI());
    }
}

9.2、Parser

用来表示非常复杂的解析器,比如解析DSL。

SQLParser
JSONParser

9.3、Customizer

用来表示对某个对象进行特别的配置。由于这些配置过程特别的复杂,值得单独提取出来进行自定义设置。

ContextCustomizer
DeviceFieldCustomizer

9.4、Formatter

格式化类。主要用于字符串、数字或者日期的格式化处理工作。

DateFormatter
StringFormatter

10、网络类

10.1、Packet

通常用于网络编程中的数据包。

DhcpPacket
PacketBuffer

10.2、Protocol

同样用户网络编程中,用来表示某个协议。

RedisProtocol
HttpProtocol

10.3、Encoder、Decoder、Codec

编码解码器

RedisEncoder
RedisDecoder
RedisCodec

10.4、Request,Response

一般用于网络请求的进和出。如果你用在非网络请求的方法上,会显得很怪异。

11、其它

11.1、Util,Helper

都表示工具类,Util一般是无状态的,Helper以便需要创建实例才能使用。但是一般没有使用Tool作为后缀的。

HttpUtil
TestKeyFieldHelper
CreationHelper

Demo1:时间转换工具类

public class DateTimeUtil {

    private static final String pattern = "yyyy-MM-dd HH:mm:ss";

    public static Long dateToTimeStamp(Date date){
        if(date == null){
            return null;
        }
        return date.getTime();
    }
}

Demo2:店铺前台类目树helper

public class ZcyShopCategoryHelper {

    /**
     * 构建key(不可随意更改)
     */
    public static String makeKeyOfCachedCategoryList(Long shopId, Long parentCategoryId) {
        return "shopCategory_shopId_" + shopId + "_parentCategoryId_" + parentCategoryId;
    }

    /**
     * 拆解key(依赖makeKeyOfCachedCategoryList)
     */
    public static Long[] parseKeyOfCachedCategoryList(String key) {
        String[] split = key.split("_");
        Long[] rtn = new Long[2];
        rtn[0] = Long.parseLong(split[2]);
        rtn[1] = Long.parseLong(split[4]);
        return rtn;
    }
}

11.2、Mode,Type

看到mode这个后缀,就能猜到这个类大概率是枚举。它通常把常见的可能性都列到枚举类里面,其他地方就可以引用这个Mode。

OperationMode
BridgeMode
ActionType

Demo1:收付方式

public enum ReceiptPaymentMode {

    TRANSFER_ACCOUNTS(1, "转账"),
    CASH(2, "现金"),
    DRAFT(3, "汇票"),
    CHECK(4, "支票");

    private final int code;
    private final String describe;
}

Demo2:业务类型

public enum BusinessType {
    SEA_IMPORT(1, "海运进口"),
    SEA_EXPORT(2, "海运出口"),
    AIR_IMPORT(3, "空运进口");

    private final Integer code;
    private final String describe;
}

11.3、Invoker,Invocation

invoker是一类接口,通常会以反射或者触发的方式,执行一些具体的业务逻辑。通过抽象出invoke方法,可以在invoke执行之前对入参进行记录或者处理;在invoke执行之后对结果和异常进行处理,是AOP中常见的操作方式。

MethodInvoker
Invoker
ConstructorInvocation

Demo:

public class ApplyInvoker {
  	 /**
     * 批量执行
     *
     * @param contexts 执行参数上下文
     * @return 执行结果
     */
    public static void batchInvoke(List<ApplyContext> contexts) {
        if (CollectionUtils.isEmpty(contexts)) {
            return;
        }
        contexts.stream().collect(Collectors.groupingBy(context -> context.getStatusChangeDTO().getApplyType())).
                forEach((type, applyContexts) -> {
                    AbstractApply apply = APPLY_MAP.get(AuditBizCode.from(type));
                    apply.batchInvoke(applyContexts);
                });
        return;
    }
}

11.4、Initializer

如果你的应用程序,需要经过大量的初始化操作才能启动,那就需要把它独立出来,专门处理初始化动作。

MultiBackgroundInitialize
ApplicationContextInitializer

Demo:数据源初始化

@Slf4j
@Lazy(false)
@Component
public class DataSourceInitializer {

    @Autowired(required = false)
    Set<DataSource> dataSources;

    @PostConstruct
    void init() {
        if (dataSources == null) {
            log.info("not any dataSource");
            return;
        }
        for (DataSource dataSource : dataSources) {
            log.info("starting dataSource: {}", dataSource);
            try {
                dataSource.getConnection();
                log.info("started dataSource: {}", dataSource);
            } catch (SQLException e) {
                log.error("start fail dataSource: {}", dataSource, e);
                throw new IllegalStateException("start fail dataSource", e);
            }
        }
    }
}

11.5、Feture,Promise

它们都是用在多线程之间的,进行数据传递

Feture相当于一个占位符,代表一个操作将来的结果。一般通过get可以直接阻塞得到结果,或者让它异步执行 然后通过callback回调结果。

但如果回调中嵌入了回调呢?如果层次很深,就是回调地狱。Java中的 CompletableFuture 其实就是 Promise,用来解决回调地狱问题。Promise是为了让代码变得优美而存在的。

11.6、Selector

根据一系列条件,获得相应的同类资源。它比较像Factory,但只处理单项资源

X509CertSelector
NodeSelector

Demo:双重校验锁获取Spi单例

public class SpiProviderSelector {

    private static SpiProviderSelector instance = null;

    private SpiProviderSelector(){}

    /**
     * Double check 获取单例
     * @return
     */
    public static SpiProviderSelector getInstance(){

        if(instance == null){
            synchronized (SpiProviderSelector.class){
                if(instance == null){
                    instance = new SpiProviderSelector();
                }
            }
        }
        return instance;
    }
}

11.7、Reporter

用来汇报某些执行结果。

ExtentHtmlReporter
MetricReporter

11.8、Constants

一般用于常量列表。

Demo:

public class Constants {
    public static final int NO = 0;
    public static final int YES = 1;

    public static final int FIVE_SECONDS = 3;

    public static final int ONE_MINUTE_IN_SECONDS = 60;

    public static final int TWO_HOURS_IN_SECONDS = 2 * 60 * 60;
}

11.9、Accessor

封装了一系列get和set方法的类。像lombok就有Accessors注解,生成这些方法。但Accessor类一般是要通过计算来完成get和set,而不是直接操作变量。这适合比较复杂的对象存取服务

ComponentAccessor
StompHeaderAccessor

11.10、Generator

生成器,一般用于生成代码,生成id等。

CodeGenerator
CipherKeyGenerator

Demo:生成redis key

public interface LockKeyGenerator {

    /**
     * 获取处理缓存key
     *
     * @param resubmitCheck    注解
     * @param request       请求
     * @param response      响应
     * @param handlerMethod 方法
     * @return
     */
    String resolverLockKey(ResubmitCheck resubmitCheck, HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947603.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊聊大厂都怎么防止重复下单?

一、问题背景 最简单的&#xff1a;DB 事务。如创建订单时&#xff0c;同时往订单表、订单商品表插数据&#xff0c;这些 Insert 须在同一事务执行。 Order 服务调用 Pay 服务&#xff0c;刚好网络超时&#xff0c;然后 Order 服务开始重试机制&#xff0c;于是 Pay 服务对同一…

java八股文面试[多线程]——自旋锁

优点&#xff1a; 1. 自旋锁尽可能的减少线程的阻塞&#xff0c;这对于锁的竞争不激烈&#xff0c;且占用锁时间非常短的代码块来说性能能大幅度的提升&#xff0c;因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗 &#xff0c;这些操作会导致线程发生两次上下文切换&…

【Python自学笔记】Python好用的模块收集(持续更新...)

文章目录 日志模块钉钉机器人命令助手持续更新中,如果您有其他实用好用的模块欢迎留言...日志模块 写代码离不开日志,自定义一个理想的日志对于小白来说可能是一件很反锁的事情,就像我刚学习Python的时候自己写的一个自定义日志,为了解决这个痛点,今天就和大家分享一个可以…

Linux开发板下检查及配置串口(波特率/数据发送接收等)的操作

在linux开发板上如何设置和编辑串口波特率、开启指定的uart口? 下面演示常用的命令操作 1&#xff09;编辑开启指定串口的配置文件 ls -l /boot/uEnv/ sudo vim /boot/uEnv/xxx.txt 2&#xff09;检查串口是否开启成功 ls /dev/tty* 3&#xff09;查看串口波特率…

每天 26,315 美元罚款?交通安全局要求特斯拉提供 Autopilot数据

根据美国国家公路交通安全管理局&#xff08;NHTSA&#xff09;最近的特别命令&#xff0c;特斯拉公司被要求提供关于其自动驾驶功能Autopilot的相关信息。这一命令是继NHTSA于2021年8月启动初步评估后&#xff0c;在2022年6月升级为正式调查的一部分&#xff0c;NHTSA近期对特…

电子电路学习笔记之NCP304LSQ37T1G ——超低电流电压检测器

超低电流电压检测器是一种专门用于检测极小电流值的设备。它们常用于电子元件或电路中&#xff0c;用于监测电流的存在和程度。这些检测器通常具有高灵敏度和高精度&#xff0c;能够测量微安级别或更小的电流。 超低电流电压检测器的应用领域广泛&#xff0c;例如电池管理系统…

宏昌转债上市价格预测

宏昌转债 基本信息 转债名称&#xff1a;宏昌转债&#xff0c;评级&#xff1a;A&#xff0c;发行规模&#xff1a;3.8亿元。 正股名称&#xff1a;宏昌科技&#xff0c;今日收盘价&#xff1a;30.5元&#xff0c;转股价格&#xff1a;29.62元。 当前转股价值 转债面值 / 转股…

Python绘图系统11:绘制极坐标图像

文章目录 旧代码整改投影下拉选框绘图逻辑源代码 Python绘图系统&#xff1a; &#x1f4c8;从0开始实现一个三维绘图系统自定义控件&#xff1a;坐标设置控件&#x1f4c9;坐标列表控件&#x1f4c9;支持多组数据的绘图系统&#x1f4c9;极坐标绘图图表类型和风格&#xff1a…

C#,《小白学程序》第九课:堆栈(Stack),先进后出

1 文本格式 /// <summary> /// 《小白学程序》第九课&#xff1a;堆栈&#xff08;Stack&#xff09; /// 堆栈与队列是相似的数据形态&#xff1b;特点是&#xff1a;先进后出&#xff1b; /// 比如&#xff1a;狭窄的电梯&#xff0c;先进去的人只能最后出来&#xff1…

【教程】DGL中的子图分区函数partition_graph讲解

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 目录 函数形式 函数作用 函数内容 函数入参 函数返参 使用示例 实际上官方的函数解释中就已经非常详细了。 函数形式 def partition_graph(g, graph_name, num_parts, out_path, num_hops1, part…

聚观早报|OpenAI宣布推出企业版ChatGPT;苹果公司开设8家新店

【聚观365】8月30日消息 OpenAI宣布推出企业版ChatGPT 比亚迪上半年净利润109.5亿元 歌尔股份上半年净利润4.22亿元 一起教育科技Q2营收6925万元 苹果公司今年开设8家新店 OpenAI宣布推出企业版ChatGPT 据外媒报道&#xff0c;当地时间周一&#xff0c;美国人工智能研究…

用XSIBackup为VMware ESXi打造完美备份方案

文章目录 VMware ESXi 备份方案引言XSIBackup安装步骤1. XSIBackup软件安装2. SSH连接3. 定位到xsibackup目录4. 修改文件权限5. 安装cron查看crontab列表6. 配置备份任务结论VMware ESXi 备份方案 引言 数据就像是我们的生命线,一旦丢失,可能会带来无法挽回的损失。对于那…

2024王道408数据结构P144 T16

2024王道408数据结构P144 T16 思考过程 首先看题目&#xff0c;要求我们把二叉树的叶子结点求出来并且用链表的方式存储&#xff0c;链接时用叶结点的右指针来存放单链表指针。我们很清楚可以看出来能用中序遍历递归的方式实现&#xff0c;因为第一个叶子结点在整棵树的最左下…

2024年java面试--集合篇

文章目录 前言ListSetMapCollectionListSetMapJDK1.7 HashMap&#xff1a;JDK1.8 HashMap&#xff1a; 一、ArrayList和LinkedList的区别二、HashSet的实现原理&#xff1f;三、List接口和Set接口的区别四、hashmap底层实现五、HashTable与HashMap的区别六、线程不安全体现七、…

基于Java+SpringBoot+Vue前后端分离医药管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

无涯教程-Android - List fragments函数

框架的ListFragment的静态库支持版本&#xff0c;用于编写在Android 3.0之前的平台上运行的应用程序&#xff0c;在Android 3.0或更高版本上运行时,仍使用此实现。 List fragment 的基本实现是用于创建fragment中的项目列表 List in Fragments 示例 本示例将向您说明如何基于…

基于饥饿游戏算法优化的BP神经网络(预测应用) - 附代码

基于饥饿游戏算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于饥饿游戏算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.饥饿游戏优化BP神经网络2.1 BP神经网络参数设置2.2 饥饿游戏算法应用 4.测试结果&#xff1a;5…

基于Java+SpringBoot+Vue前后端分离文理医院预约挂号系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

AD域控统一设置桌面壁纸

这里的UNC路径是在C盘建立的共享文件夹Desktop 最后更新一下策略就可以了。

yolo增加RFEM

论文地址&#xff1a;https://arxiv.org/pdf/2208.02019.pdf 代码地址&#xff1a;GitHub - Krasjet-Yu/YOLO-FaceV2: YOLO-FaceV2: A Scale and Occlusion Aware Face Detector 总的来说就是RFEM利用了感受野在特征图中的优势&#xff0c;通过使用不同膨胀卷积率的分支来捕捉多…