当前位置: 首页 > news >正文

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

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

无规范不成方圆。我自己非常注重搭建项目结构的起步过程,应用命名规范、模块的划分、目录(包)的命名,我觉得非常重要,如果做的足够好,别人导入项目后可能只需要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 {@Resourceprivate ExtensionRegister extensionRegister;private ApplicationContext applicationContext;@PostConstructpublic void init() {Map<String, Object> extensionBeans = applicationContext.getBeansWithAnnotation(Extension.class);extensionBeans.values().forEach(extension -> extensionRegister.doRegistration((ExtensionPointI) extension));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

Demo2:MQ消费者启动

@Slf4j
@Component
public class mqConsumerStarter implements ApplicationRunner {@Autowired(required = false)Set<MessageCallback> messageCallbackSet;@Autowiredprivate MQTemplate mqTemplate;@Autowiredprivate mqAsyncRetryConsumer mqAsyncRetryConsumer;@Overridepublic void run(ApplicationArguments args) throws Exception {registerAllConsumer();}
}

1.2、Processor

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

CompoundProcessor
BinaryComparisonProcessor

Demo:车队订单处理器

@Slf4j
@Component
public class ConveyOrderProcessor {@RpcConsumerprivate 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 {@Autowiredprivate 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 {@Beanpublic DistributedTransactionPolicyProperties distributedTransactionPolicyProperties(){return new DistributedTransactionPolicyProperties();}@Beanpublic DistributedTransactionDao distributedTransactionDao(){return new DistributedTransactionDao();}@Beanpublic 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;@Overridepublic void run() {process();}protected abstract boolean process();@Overridepublic long getDelay(TimeUnit unit) {return 0;}@Overridepublic 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 {@Autowiredprivate BatchJobWriteFacade batchJobWriteFacade;@Autowiredprivate mqConsumerManager consumerManager;public void init() throws MQException {Map<String, MessageCallback> map = Maps.newHashMap();map.put(getConsumerId(), ImConsumerEnhanceUtil.enhanceAll(getConsumerId(), this));consumerManager.listenMessage(map);}@Overridepublic void run(ApplicationArguments args) throws Exception {init();}@Overridepublic 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")@EventListenerpublic 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 {@Autowiredprivate mqConsumerManager consumerManager;private ApplicationContext applicationContext;@Overridepublic 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;}}@Overridepublic 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());}@Overridepublic 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);}}@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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, skuCoderuleExecutorRegistry.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));//spuruleExecutorRegistry.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;// invokeResult 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 {@Autowiredprivate 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);}// 默认校验器@Overridepublic 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 {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 执行代码增强逻辑...}@Overridepublic Object plugin(Object target) {}@Overridepublic void setProperties(Properties properties) {}
}

Demo2:SpringMVC 防重提交拦截器

@Component
@Slf4j
public class ResubmitCheckInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {...}@Overridepublic 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 {@Autowiredprivate 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));}/*** 限流*/@Overridepublic void acquire(int permits) {...}
}

Demo2:商品发布频率限制

@Slf4j
@Component
public class ItemFrequencyLimiter implements ItemRiskControlLimiter {@Overridepublic Boolean preLimit(String apolloRuleKey, LoginUser loginUser) {}@Overridepublic 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> {@Overridepublic 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@AllowConcurrentEventspublic 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 {@Autowiredprivate OrderFsmEngine orderFsmEngine;@Overridepublic boolean when(OrderInfo orderInfo, Integer orderState) {...}@Overridepublic ServiceResponse<Long> check(OrderInfo orderInfo, Integer orderState) {}@Overridepublic ServiceResponse<Long> then(OrderInfo orderInfo, Long updateUser) {...}@Overridepublic 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 {@Overridepublic Response<Boolean> excute(ScanActionContext scanActionContext) {...}@Overridepublic ScanResult getResult(Long categoryId) {...}@Overridepublic 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;@Overridepublic ConvoyOrderEvent getEventType() {return ConvoyOrderEvent.CREATE;}
}

8.5、Delegate 委托模式

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

LayoutlibDelegate
FragmentDelegate

Demo:

@Slf4j
@Service
public class CustomerDoorsDelegateService {@Autowiredprivate 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> {@Autowiredprivate BizDiffMapper bizDiffMapper;// 模版方法public final boolean inspectionMethod() {Stopwatch stopwatch = Stopwatch.createStarted();BizContext<T> context;try {if (isProcessing()) {//任务正在执行中log.warn("当前任务正在执行,本次执行忽略: 唯一键{}", getExecutorKey());return false;}context = fillBizData();// 获取batchIdinitBatchId(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 {@Autowiredprivate CloudServiceItemWriteApi cloudServiceItemWriteApi;public Response<ItemIdDTO> create(ItemCreateCmd createCmd) {//岛端创建基础商品,需要将仓库编码置为nullif(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 {@Overridepublic 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;@PostConstructvoid 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);
}

相关文章:

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

研发规范第九讲&#xff1a;通用类命名规范&#xff08;重点&#xff09; 无规范不成方圆。我自己非常注重搭建项目结构的起步过程&#xff0c;应用命名规范、模块的划分、目录&#xff08;包&#xff09;的命名&#xff0c;我觉得非常重要&#xff0c;如果做的足够好&#xff…...

python+django+协同过滤算法-基于爬虫的个性化书籍推荐系统(包含报告+源码+开题)

为了提高个性化书籍推荐信息管理的效率&#xff1b;充分利用现有资源&#xff1b;减少不必要的人力、物力和财政支出来实现管理人员更充分掌握个性化书籍推荐信息的管理&#xff1b;开发设计专用系统--基于爬虫的个性化书籍推荐系统来进行管理个性化书籍推荐信息&#xff0c;以…...

系统架构:软件工程

文章目录 资源知识点自顶向下与自底向上形式化方法结构化方法敏捷方法净室软件工程面向服务的方法面向对象的方法快速应用开发螺旋模型软件过程和活动开放式源码开发方法功用驱动开发方法统一过程模型RUP基于构件的软件开发UML 资源 信息系统开发方法 知识点 自顶向下与自底…...

泰迪大数据实训平台产品介绍

大数据产品包括&#xff1a;大数据实训管理平台、大数据开发实训平台、大数据编程实训平台等 大数据实训管理平台 泰迪大数据实训平台从课程管理、资源管理、实训管理等方面出发&#xff0c;主要解决现有实验室无法满足教学需求、传统教学流程和工具低效耗时和内部教学…...

Linux- 文件夹相关的常用指令

1. 统计文件夹下的文件数量 在 Linux 下&#xff0c;有几种方法可以统计文件夹下的文件数量&#xff1a; 使用 ls 和 wc 命令&#xff1a; 这种方式可以统计目录下的直接子文件&#xff08;不包括子目录里的文件&#xff09;。 ls -l <目录路径> | wc -l注意&#xff1a…...

在 macOS 中安装 TensorFlow 1g

tensorflow 需要多大空间 pip install tensorflow pip install tensorflow Looking in indexes: https://pypi.douban.com/simple/ Collecting tensorflowDownloading https://pypi.doubanio.com/packages/1a/c1/9c14df0625836af8ba6628585c6d3c3bf8f1e1101cafa2435eb28a7764…...

数学建模:CRITIC赋权法

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 CRITIC赋权法 算法流程 构建原始数据矩阵 X X X&#xff0c;他是一个 m ∗ n m * n m∗n 的矩阵&#xff0c; m m m 表示评价对象个数&#xff0c; n n n 表示指标个数对原始数据矩阵进行正向化处理计算…...

Facebook message tag 使用攻略

Messenger 讯息传不出去&#xff1f;无法发送FB 讯息给非好友&#xff1f; 2020年3月&#xff0c;Facebook 为了防止用户被过多的推广或垃圾讯息困扰而更新使用条款&#xff0c;现在商家要用FB传讯息给所有人&#xff08;包括非好友&#xff09;&#xff0c;应该使用 Facebook …...

气传导耳机哪个品牌比较好?综合表现很不错的气传导耳机推荐

​气传导耳机不仅能够提升幸福感还能听到周围环境声&#xff0c;大大提高安全性。如果你在寻找一款高品质的气传导耳机&#xff0c;又不知从何入手时&#xff0c;不要担心&#xff0c;我已经为你精心挑选了四款市面上综合表现很不错的气传导耳机&#xff0c;让你享受更好的音质…...

Rabbitmq的消息转换器

Spring会把你发送的消息序列化为字节发送给MQ&#xff0c;接收消息的时候&#xff0c;还会把字节反序列化为Java对象 ,只不过&#xff0c;默认情况下Spring采用的序列化方式是JDK序列化。众所周知&#xff0c;JDK序列化存在下列问题&#xff1a; 数据体积过大 有安全漏洞 可读…...

nvidia-docker的使用

拉取镜像 docker pull nvidia/cuda可能出现的问题 问题描述 Error response from daemon: manifest for nvidia/cuda:latest not found: manifest unknown: manifest解决方法&#xff1a; 为找到正确且合适的docker镜像版本 在supported-tags中找到与自己系统对应的cuda版本…...

C++新经典 | C语言

目录 一、基础之查漏补缺 1.float精度问题 2.字符型数据 3.变量初值问题 4.赋值&初始化 5.头文件之<> VS " " 6.逻辑运算 7.数组 7.1 二维数组初始化 7.2 字符数组 8.字符串处理函数 8.1 strcat 8.2 strcpy 8.3 strcmp 8.4 strlen 9.函数 …...

物联网智慧种植农业大棚系统

一、项目背景 智慧农业是是将物联网技术和农业生产箱管理的新型农业&#xff0c;依托部署在农业生产现场的各种传感节点&#xff0c;以物联网网关为通道形成数据传输网络&#xff0c;可以实现控制柜、环境监测传感器、气象监测机器等设备的远程监控&#xff0c;达到及时高校的…...

TabBar组件如何跳转页面?

1、先引入 2、假数据 const tabs [{key: home,title: 首页,icon: <AppOutline />,badge: Badge.dot,},{key: todo,title: 待办,icon: <UnorderedListOutline />,badge: 5,},{key: message,title: 消息,icon: (active: boolean) >active ? <MessageFill /&…...

Vue.js中,router和route

<div class"search">{{$route.params.things}}<van-nav-bar fixed title"商品列表" left-arrow click-left"$router.go(-1)" /><van-searchreadonlyshape"round"background"#ffffff"value"手机"sh…...

【微服务】07-缓存

文章目录 为不同的场景设计合适的缓存策略1. 缓存是什么2. 缓存的场景3. 缓存的策略4. 缓存位置5. 缓存实现的要点6. 注意问题7. 使用的组件8. 内存缓存和分布式缓存区别 总结 为不同的场景设计合适的缓存策略 1. 缓存是什么 缓存是计算结果的“临时”存储和重复使用缓存本质…...

权限校验中的“双token”方案

1. 双Token中的两个token分别是什么&#xff1f; 1.1 access_token 1.2 fresh_token 2. 为什么需要双token&#xff1f;一个token不行吗&#xff1f; 答&#xff1a; 两个token的职责不同。其中&#xff0c;access_token是在每次请求的时候携带给后端进行权限校验&#xff…...

TensorFlow的基本概念

TensorFlow 是由 Google 开发的开源机器学习框架&#xff0c;其基本概念如下&#xff1a; 1. 张量&#xff08;Tensor&#xff09;&#xff1a;TensorFlow 中最基本的数据结构&#xff0c;是多维数组&#xff0c;可以理解为向量或矩阵的推广。常见的张量有常量张量、变量张量和…...

【卷积神经网络】MNIST 手写体识别

LeNet-5 是经典卷积神经网络之一&#xff0c;1998 年由 Yann LeCun 等人在论文 《Gradient-Based Learning Applied to Document Recognition》中提出。LeNet-5 网络使用了卷积层、池化层和全连接层&#xff0c;实现可以应用于手写体识别的卷积神经网络。TensorFlow 内置了 MNI…...

Ansible学习笔记2

Ansible是Python开发的自动化运维工具&#xff0c;集合了众多运维工具&#xff08;Puppet、cfengine、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置&#xff0c;批量程序部署、批量运行命令等功能。 特点&#xff1a; 1&#xff09;部署简单&#xff…...

80. 删除有序数组中的重复项 II

【中等题】 题目&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额…...

CVE-2023-36874 Windows错误报告服务本地权限提升漏洞分析

CVE-2023-36874 Windows错误报告服务本地权限提升漏洞分析 漏洞简介 Windows错误报告服务在提交错误报告前会创建wermgr.exe进程&#xff0c;而攻击者使用特殊手法欺骗系统创建伪造的wermgr.exe进程&#xff0c;从而以system权限执行代码。 影响版本 Windows10 1507 * Wind…...

IDEA遇到 git pull 冲突的几种解决方法

1 忽略本地修改&#xff0c;强制拉取远程到本地 主要是项目中的文档目录&#xff0c;看的时候可能多了些标注&#xff0c;现在远程文档更新&#xff0c;本地的版本已无用&#xff0c;可以强拉 git fetch --all git reset --hard origin/dev git pull关于commit和pull的先后顺…...

[Unity]UI和美术出图效果不一致

问题描述&#xff1a;美术使用PS在Gamma空间下设计的UI图&#xff0c;导入到Unity&#xff0c;因为Unity使用的是线性空间&#xff0c;导致半透明的UI效果和美术设计的不一致。 解决方案&#xff1a; &#xff08;一&#xff09;让美术在线性空间下工作 &#xff08;二&…...

SpringBoot整合JPA和Hibernate框架

Springboot整合JPAHibernate框架【待完成】 随着MybatisPlus技术的发展&#xff0c;JPA和Hibernate技术已经逐步淘汰 JPA遵循了Hibernate框架规则&#xff0c;目前使用的不多 1、添加依赖 <!--jpa--> <dependency><groupId>org.springframework.boot</…...

Java中文件的创建(三种方式),文件常用的方法

文件的创建 方式1&#xff1a; new File(String pathName) 根据路径构建一个File对象方式2&#xff1a; new File(File parent,String child) 根据父目录文件子路径构建方式3&#xff1a; new File(String parent,String child) 根据父目录子路径构建 代码&#xff1a; //方…...

Spring boot中调用C/C++(dll)

添加JNA依赖 <dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>5.5.0</version> </dependency>准备C代码/C代码 如下是C代码&#xff0c;文件名&#xff1a;xizi.c #include <std…...

【Apollo学习笔记】——规划模块TASK之PATH_DECIDER

文章目录 前言PATH_DECIDER功能简介PATH_DECIDER相关配置PATH_DECIDER总体流程路径决策代码流程及框架MakeStaticObstacleDecision PATH_DECIDER相关子函数参考 前言 在Apollo星火计划学习笔记——Apollo路径规划算法原理与实践与【Apollo学习笔记】——Planning模块讲到……S…...

Lua学习(二)

Lua基础学习 7. lua函数8. lua运算符8.1 算数运算符8.2 关系运算符8.3 逻辑运算符8.4 其他运算符 9. lua字符串9.1 字符串格式化9.2 匹配模式 10. lua数组11. lua迭代器11.1 Lua table 12. lua 模块12.1 加载机制12.2 C 包 接着上一篇的内容。Lua学习&#xff08;一&#xff09…...

制作鲜花商城小程序的详细步骤

如果你是一个新手商家&#xff0c;想要进入鲜花团购市场&#xff0c;但是不知道如何制作一个小程序商城&#xff0c;那么这篇文章就是为你准备的。以下是制作鲜花团购小程序商城的详细步骤&#xff1a; 1. 登录乔拓云平台后台&#xff0c;进入商城管理页面 首先&#xff0c;你需…...

Ubuntu20以上高版本如何安装低版本GCC

安装了Ubuntu 20.04之后&#xff0c;通过命令行 sudo apt-get install build-essential安装gcc&#xff0c;再通过命令行 gcc -v可查看gcc版本为gcc13 如果想用低版本的gcc&#xff0c;比如gcc4.8&#xff0c;尝试输入命令 sudo apt-get install gcc-4.8会提示找不到gcc4.8的…...

context.WithCancel()的使用

“ WithCancel可以将一个Context包装为cancelCtx,并提供一个取消函数,调用这个取消函数,可以Cancel对应的Context Go语言context包-cancelCtx[1] 疑问 context.WithCancel()取消机制的理解[2] 父母5s钟后出门&#xff0c;倒计时&#xff0c;父母在时要学习&#xff0c;父母一走…...

vue3中引入百度地图

话不多说直接开干 1.第一种方式 百度地图地址 打开 https://lbsyun.baidu.com/index.php?title%E9%A6%96%E9%A1%B5 然后点进去地图 然后再这个功能里面选择一个地图&#xff0c;然后跳转页面 然后一直下滑 滑到底部 点击这个 跳转到这个页面 然后点击进入demo这个 然后到这个…...

【Linux-Day8- 进程替换和信号】

进程替换和信号 问题引入 我们发现 终端输入的任意命令的父进程都是bash,这是因为Linux系统是用fork()复制出子进程&#xff0c;然后在子进程中调用替换函数进行进程替换&#xff0c;实现相关命令。 &#xff08;1&#xff09; exec 系列替换过程&#xff1a;pcb 使用以前的只…...

日志文件之间关系和介绍及应用

1.常用日志框架代码举例 Log4j: Log4j是Java中广泛使用的日志框架之一。它提供了灵活的配置选项和丰富的功能&#xff0c;支持日志级别、日志输出目标等。Log4j有1.x版本和2.x版本&#xff0c;其中Log4j 2.x是对1.x的升级和扩展。 Logback: Logback是由Log4j创始人设计的Log4…...

mac电脑屏幕录制Berrycast Mac屏幕录制软件

Berrycast是一款为Mac设计的优秀屏幕录制软件&#xff0c;它让屏幕录制变得简单而高效。以下是Berrycast的一些主要特点&#xff1a; 简单的用户界面&#xff1a;Berrycast拥有直观和简洁的用户界面&#xff0c;使得用户可以轻松上手。高质量的视频输出&#xff1a;Berrycast能…...

机器学习笔记之最优化理论与方法(一)最优化问题概述

机器学习笔记之最优化理论与方法——最优化问题概述 引言什么是最优化问题最优化问题的基本形式最优化问题的分类各分类最优化问题的数学表达约束优化VS无约束优化线性规划VS非线性规划连续优化VS离散优化单目标优化VS多目标优化 引言 从本节开始&#xff0c;将对最优化理论与…...

【ES5新特性一】 严格模式语法变化、全局的JSON对象、编码和解码的方法

前言 ECMAScript 和 JavaScript 的关系 一个常见的问题是&#xff0c;ECMAScript 和 JavaScript 到底是什么关系&#xff1f; 要讲清楚这个问题&#xff0c;需要回顾历史。1996 年 11 月&#xff0c;JavaScript 的创造者 Netscape 公司&#xff0c;决定将 JavaScript 提交给标准…...

Java【手撕滑动窗口】LeetCode 3. “无重复字符的最长子串“, 图文详解思路分析 + 代码

文章目录 前言一、长度最小子数组1, 题目2, 思路分析3, 代码 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等 &#x1f4d7; Java数据结构: 顺序表, 链…...

学习哈哈哈哈

# 零、学习计划 * 数据库相关 * 索引 * [我以为我对数据库索引很了解&#xff0c;直到我遇到了阿里面试官 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/107487215) * [给我一分钟&#xff0c;让你彻底明白MySQL聚簇索引和非聚簇索引 - 知乎 (zhihu.com)](ht…...

05-基础例程5

基础例程5 1、超声波测距 实验介绍 ​ HC-SR04超声波传感器是一款测量距离的传感器。其原理是利用声波在遇到障碍物反射接收结合声波在空气中传播的速度计算的得出。 外观 管脚功能的定义 VCC&#xff1a;供电电源&#xff1b;Trig&#xff1a;触发信号&#xff1b;Echo&a…...

双基证券:预计未来还会有更多政策来吸引增量资金

双基证券表示&#xff0c;8月27日&#xff0c;活泼资本商场五大方针出台&#xff1a;证券交易印花税折半征收&#xff1b;阶段性收紧IPO节奏&#xff1b;上市房企再融资不受破发、破净和亏本限制&#xff1b;标准控股股东与实际操控人减持行为&#xff1b;融资保证金最低份额由…...

前端:html实现页面切换、顶部标签栏,类似于浏览器的顶部标签栏(完整版)

效果 代码 <!DOCTYPE html> <html><head><style>/* 左侧超链接列表 */.link {display: block;padding: 8px;background-color: #f2f2f2;cursor: pointer;}/* 顶部标签栏 */#tabsContainer {width:98%;display: flex;align-items: center;overflow-x: …...

强化自主可控,润开鸿发布基于RISC-V架构的开源鸿蒙终端新品

2023 RISC-V中国峰会于8月23日至25日在北京召开,峰会以“RISC-V生态共建”为主题,结合当下全球新形势,把握全球新时机,呈现RISC-V全球新观点、新趋势。本次大会邀请了RISC-V国际基金会、业界专家、企业代表及社区伙伴等共同探讨RISC-V发展趋势与机遇,吸引超过百余家业界企业、高…...

软件设计师知识点·1

控制器: (1)指令寄存器(IR) : CPU执行一条指令时,从内存储器取到缓冲寄存器中,再送入IR暂存; (2)程序计数器(PC): 将要执行的下一条指令的地址; (3)地址寄存器(IR): 当前CPU所访问的内存单元地址; (4)指令译码器(ID): 对指令中的操作码字段进行分析解释; 多核CPU可以满足用户…...

修改Jupyter Notebook默认打开路径

这里我是重新下载的anaconda&#xff0c;打开Jupyter之后是默认在C盘的一个路径的&#xff0c;现在我们就来修改一下它的一个默认打开路径&#xff0c;这样在我们后续学习过程中&#xff0c;可以将ipynb后缀的文件放在这个目录下就能查看了。 1、先打开Anaconda Prompt&#x…...

经典卷积网络

目录 一、经典神经网络出现的时间线​编辑 二、LeNet 三、AlexNet 四、VGGNet 五、InceptionNet 六、ResNet 总结&#xff1a; 一、经典神经网络出现的时间线 二、LeNet 背景&#xff1a;LeNet由Yann LeCun于1998年提出&#xff0c;卷积网络开篇之作。 解释&#xff1…...

react+koa+vite前后端模拟jwt鉴权过程

路由组件&#xff08;生成token&#xff09; const Router require(koa/router) const jwt require(jsonwebtoken); const router new Router()const mockDbUserInfo [{nickname: xxxliu,username: Tom,password: 123456,icon: url1},{nickname: xxx,username: John,passw…...

VK1616是LED显示控制驱动电路/LED驱动IC、数显驱动芯片、数码管驱动芯片

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK1616 封装形式&#xff1a;SOP16 产品年份&#xff1a;新年份 概述&#xff1a;VK1616是一种数码管或点阵LED驱动控制专用芯片&#xff0c;内部集成有3线串行接口、数据锁存器、LED 驱动等电路。SEG脚接LED阳极&a…...

开箱报告,Simulink Toolbox库模块使用指南(五)——S-Fuction模块(C MEX S-Function)

文章目录 前言 C MEX S-Function 算法原理 原始信号创建 编写S函数 仿真验证 Tips 分析和应用 总结 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;一&#xff09;——powergui模块》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用…...