策略工厂
定义策略接口,多个实现类,定义策略工厂,构造方法通过Spring 容器自动获取实现类List集合,遍历List按照每个实现类策略类型逐个插入Map
public interface PayHandler { void pay(PayCommand command); String getPayType(); // 获取支付类型(例如:支付宝,微信) } @Service("ALI") public class AliPayHandler implements PayHandler { @Override public void pay(PayCommand command) { // 支付宝支付逻辑 System.out.println("支付宝支付,支付金额:" + command.getAmount()); } @Override public String getPayType() { return "ALI"; // 支付宝支付类型 } } @Service("WECHAT") public class WeChatPayHandler implements PayHandler { @Override public void pay(PayCommand command) { // 微信支付逻辑 System.out.println("微信支付,支付金额:" + command.getAmount()); } @Override public String getPayType() { return "WECHAT"; // 微信支付类型 } } @Component public class PayHandlerFactory { private final Map<String, PayHandler> handlerMap; @Autowired public PayHandlerFactory(List<PayHandler> handlerList) { handlerMap = new HashMap<>(); // 遍历 handlerList,将每个策略和支付类型关联起来 for (PayHandler handler : handlerList) { handlerMap.put(handler.getPayType(), handler); } } public PayHandler getHandler(String payType) { PayHandler handler = handlerMap.get(payType); if (handler == null) { throw new IllegalArgumentException("不支持的支付方式: " + payType); } return handler; } }动态代理
代理类在运行期自动生成,无需手动实现
JDK动态代理(基于接口)
public interface OrderService { void createOrder(); } public class OrderServiceImpl implements OrderService { @Override public void createOrder() { System.out.println("👉 执行业务:创建订单"); } } import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LogInvocationHandler implements InvocationHandler { private final Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法前增强 System.out.println("🟢 方法前:记录日志 / 幂等校验 / 事务开始"); // 调用目标方法 Object result = method.invoke(target, args); // 方法后增强 System.out.println("🔵 方法后:提交事务 / 记录日志"); return result; } } import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { // 1️⃣ 目标对象 OrderService target = new OrderServiceImpl(); // 2️⃣ 创建代理对象 OrderService proxy = (OrderService) Proxy.newProxyInstance( target.getClass().getClassLoader(), // 类加载器 target.getClass().getInterfaces(), // 代理的接口 new LogInvocationHandler(target) // 方法拦截器 ); // 3️⃣ 调用代理方法 proxy.createOrder(); } }CGLIB动态代理(基于继承)
二、目标类(⚠️ 没有接口) public class OrderService { public void createOrder() { System.out.println("👉 执行业务:创建订单"); } } 三、MethodInterceptor(核心拦截器) import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class LogMethodInterceptor implements MethodInterceptor { @Override public Object intercept( Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 方法前增强 System.out.println("🟢 方法前:记录日志 / 事务开始"); // ⚠️ 调用父类方法(不是反射) Object result = proxy.invokeSuper(obj, args); // 方法后增强 System.out.println("🔵 方法后:提交事务"); return result; } } 📌 重点: invokeSuper() → 调用父类方法 不是 method.invoke()(性能更好) 四、创建代理对象(关键代码) import net.sf.cglib.proxy.Enhancer; public class CglibProxyTest { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); // 1️⃣ 设置父类(目标类) enhancer.setSuperclass(OrderService.class); // 2️⃣ 设置方法拦截器 enhancer.setCallback(new LogMethodInterceptor()); // 3️⃣ 创建代理对象(子类实例) OrderService proxy = (OrderService) enhancer.create(); // 4️⃣ 调用方法 proxy.createOrder(); } } 五、运行时 JVM 实际生成的类(核心理解) JVM 运行期生成的代理类类似: class OrderService$$EnhancerByCGLIB extends OrderService { @Override public void createOrder() { interceptor.intercept(...); } } 📌 这就是“基于继承”的直接体现 六、执行流程(一定要理解) proxy.createOrder() ↓ 子类重写方法 ↓ MethodInterceptor.intercept() ↓ invokeSuper() 调用父类 ↓ OrderService.createOrder()Spring AOP
底层技术实现动态代理,上层通过切面思想和注解优化了实现
二、定义一个【幂等注解】 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Idempotent { /** * 幂等key的 SpEL 表达式 * 例如:#msg.orderId */ String key(); /** * 幂等超时时间(秒) */ long timeout() default 300; } 📌 关键点: SpEL 表达式 → 不侵入业务 不绑定 MQ、HTTP、RPC → 通用 三、RocketMQ 消费者(业务代码极简) @RocketMQMessageListener( topic = "ORDER_PAY_SUCCESS", consumerGroup = "order-consumer-group" ) @Component public class OrderPaySuccessConsumer implements RocketMQListener<OrderPayMsg> { @Override @Idempotent(key = "'ORDER_PAY_' + #msg.orderId") public void onMessage(OrderPayMsg msg) { // ✅ 这里不写任何幂等代码 orderService.handlePaySuccess(msg.getOrderId()); } } ✅ 你会发现: MQ 重试 重复投递 幂等控制 业务代码完全无感知 四、AOP 幂等切面(核心) @Aspect @Component public class IdempotentAspect { @Autowired private RedissonClient redissonClient; @Around("@annotation(idempotent)") public Object around(ProceedingJoinPoint pjp, Idempotent idempotent) throws Throwable { Method method = ((MethodSignature) pjp.getSignature()).getMethod(); // 1️⃣ 解析 SpEL,生成幂等 key String key = parseKey(idempotent.key(), method, pjp.getArgs()); String redisKey = "IDEMPOTENT:" + key; // 2️⃣ Redis 原子占位 RBucket<String> bucket = redissonClient.getBucket(redisKey); boolean success = bucket.trySet( "PROCESSING", idempotent.timeout(), TimeUnit.SECONDS ); if (!success) { // 🚫 幂等命中,直接返回 return null; } try { // 3️⃣ 执行业务逻辑 Object result = pjp.proceed(); // 4️⃣ 标记成功 bucket.set("SUCCESS", idempotent.timeout(), TimeUnit.SECONDS); return result; } catch (Exception e) { // ❗ 异常要删除 key,允许 MQ 重试 bucket.delete(); throw e; } } }责任链模式
当执行业务逻辑前有很多条校验时采取责任链模式提升代码复用性和扩展性
定义一个责任链最高层接口,多个责任链模式接口,每个责任链模式接口多个实现类,把每个责任链模式的实现类根据定义好的Order排序存到List,再根据对应责任链模式存到Map
public interface AbstractChainHandler<T> extends Ordered { /** * 执行责任链逻辑 * * @param requestParam 责任链执行入参 */ void handler(T requestParam); /** * @return 责任链组件标识 */ String mark(); } public interface TrainPurchaseTicketChainFilter<T extends PurchaseTicketReqDTO> extends AbstractChainHandler<PurchaseTicketReqDTO> { @Override default String mark() { return TicketChainMarkEnum.TRAIN_PURCHASE_TICKET_FILTER.name(); } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamNotNullChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { @Override public void handler(PurchaseTicketReqDTO requestParam) { if (StrUtil.isBlank(requestParam.getTrainId())) { throw new ClientException("列车标识不能为空"); } if (StrUtil.isBlank(requestParam.getDeparture())) { throw new ClientException("出发站点不能为空"); } if (StrUtil.isBlank(requestParam.getArrival())) { throw new ClientException("到达站点不能为空"); } if (CollUtil.isEmpty(requestParam.getPassengers())) { throw new ClientException("乘车人至少选择一位"); } for (PurchaseTicketPassengerDetailDTO each : requestParam.getPassengers()) { if (StrUtil.isBlank(each.getPassengerId())) { throw new ClientException("乘车人不能为空"); } if (Objects.isNull(each.getSeatType())) { throw new ClientException("座位类型不能为空"); } } } @Override public int getOrder() { return 0; } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamVerifyChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { private final TrainMapper trainMapper; private final TrainStationMapper trainStationMapper; private final DistributedCache distributedCache; @Override public void handler(PurchaseTicketReqDTO requestParam) { // 查询会员购票车次是否存在,通过封装后安全的 Get 方法 TrainDO trainDO = distributedCache.safeGet( TRAIN_INFO + requestParam.getTrainId(), TrainDO.class, () -> trainMapper.selectById(requestParam.getTrainId()), ADVANCE_TICKET_DAY, TimeUnit.DAYS); if (Objects.isNull(trainDO)) { // 如果按照严谨逻辑,类似异常应该记录当前用户的 userid 并发送到风控中心 // 如果一段时间有过几次的异常,直接封号处理。下述异常同理 throw new ClientException("请检查车次是否存在"); } // TODO,当前列车数据并没有通过定时任务每天生成最新的,所以需要隔离这个拦截。后期定时生成数据后删除该判断 if (!EnvironmentUtil.isDevEnvironment()) { // 查询车次是否已经发售 if (new Date().before(trainDO.getSaleTime())) { throw new ClientException("列车车次暂未发售"); } // 查询车次是否在有效期内 if (new Date().after(trainDO.getDepartureTime())) { throw new ClientException("列车车次已出发禁止购票"); } } // 车站是否存在车次中,以及车站的顺序是否正确 String trainStationStopoverDetailStr = distributedCache.safeGet( TRAIN_STATION_STOPOVER_DETAIL + requestParam.getTrainId(), String.class, () -> { LambdaQueryWrapper<TrainStationDO> queryWrapper = Wrappers.lambdaQuery(TrainStationDO.class) .eq(TrainStationDO::getTrainId, requestParam.getTrainId()) .select(TrainStationDO::getDeparture); List<TrainStationDO> actualTrainStationList = trainStationMapper.selectList(queryWrapper); return CollUtil.isNotEmpty(actualTrainStationList) ? JSON.toJSONString(actualTrainStationList) : null; }, Index12306Constant.ADVANCE_TICKET_DAY, TimeUnit.DAYS ); List<TrainStationDO> trainDOList = JSON.parseArray(trainStationStopoverDetailStr, TrainStationDO.class); boolean validateStation = validateStation( trainDOList.stream().map(TrainStationDO::getDeparture).toList(), requestParam.getDeparture(), requestParam.getArrival() ); if (!validateStation) { throw new ClientException("列车车站数据错误"); } } @Override public int getOrder() { return 10; } public boolean validateStation(List<String> stationList, String startStation, String endStation) { int index1 = stationList.indexOf(startStation); int index2 = stationList.indexOf(endStation); if (index1 == -1 || index2 == -1) { return false; } return index2 >= index1; } } @Component @RequiredArgsConstructor public class TrainPurchaseTicketParamStockChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> { private final SeatMarginCacheLoader seatMarginCacheLoader; private final DistributedCache distributedCache; @Override public void handler(PurchaseTicketReqDTO requestParam) { // 车次站点是否还有余票。如果用户提交多个乘车人非同一座位类型,拆分验证 String keySuffix = StrUtil.join("_", requestParam.getTrainId(), requestParam.getDeparture(), requestParam.getArrival()); StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) distributedCache.getInstance(); List<PurchaseTicketPassengerDetailDTO> passengerDetails = requestParam.getPassengers(); Map<Integer, List<PurchaseTicketPassengerDetailDTO>> seatTypeMap = passengerDetails.stream() .collect(Collectors.groupingBy(PurchaseTicketPassengerDetailDTO::getSeatType)); seatTypeMap.forEach((seatType, passengerSeatDetails) -> { Object stockObj = stringRedisTemplate.opsForHash().get(TRAIN_STATION_REMAINING_TICKET + keySuffix, String.valueOf(seatType)); int stock = Optional.ofNullable(stockObj).map(each -> Integer.parseInt(each.toString())).orElseGet(() -> { Map<String, String> seatMarginMap = seatMarginCacheLoader.load(String.valueOf(requestParam.getTrainId()), String.valueOf(seatType), requestParam.getDeparture(), requestParam.getArrival()); return Optional.ofNullable(seatMarginMap.get(String.valueOf(seatType))).map(Integer::parseInt).orElse(0); }); if (stock >= passengerSeatDetails.size()) { return; } throw new ClientException("列车站点已无余票"); }); } @Override public int getOrder() { return 20; } } public final class AbstractChainContext<T> implements CommandLineRunner { private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>(); /** * 责任链组件执行 * * @param mark 责任链组件标识 * @param requestParam 请求参数 */ public void handler(String mark, T requestParam) { List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark); if (CollectionUtils.isEmpty(abstractChainHandlers)) { throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark)); } abstractChainHandlers.forEach(each -> each.handler(requestParam)); } @Override public void run(String... args) throws Exception { Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder .getBeansOfType(AbstractChainHandler.class); chainFilterMap.forEach((beanName, bean) -> { List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark()); if (CollectionUtils.isEmpty(abstractChainHandlers)) { abstractChainHandlers = new ArrayList(); } abstractChainHandlers.add(bean); List<AbstractChainHandler> actualAbstractChainHandlers = abstractChainHandlers.stream() .sorted(Comparator.comparing(Ordered::getOrder)) .collect(Collectors.toList()); abstractChainHandlerContainer.put(bean.mark(), actualAbstractChainHandlers); }); } }