不想造轮子的程序员成为不了技术专家 #

作者介绍 #

小马哥,一个不是在造轮子,就是在造轮子路上的程序员,追求优雅编码。写过博客,参与过开源项目,热衷于基础架构。

星球介绍 #

做星球的初衷,希望通过商城项目,模拟出日常开发的不同难题,并给出合适的解决方案,帮助大家收获成长!

小马哥以为,星球还是要以 代码实战课 为中心,围绕以下五个点进行讲述:

1)DDD 开发模式 #

DDD 全称为(Domain-Driven Design,简称 DDD),领域驱动设计。

在互联网初期,对于一些简单的业务,只需要使用一个项目,编写多个业务逻辑就可以搞定,也就是最初的 单体项目阶段

随着互联网的的发展,以及业务复杂度增长,分布式技术快速兴起,将单体项目根据业务拆分为多个服务,就到了 微服务时代

但是,随着业务越来越复杂,当需要修改其中某项功能时,发现不太容易修改,因为改了这个功能后会 引起其它模块代码的级联反应。造成开发者业务开发周期增加,人力成本过高等问题。

DDD 模型可以很好的解决上述问题。所以,星球产出的商城系统会在 多个业务模块中使用 DDD 开发,梳理业务模型,帮助对 DDD 一知半解的开发者树立正确的开发思路。

2)商城业务 #

大部分同学在开发简单业务系统中,很难遇到有挑战性的技术难点,这也是导致技术进步缓慢的主要问题。

星球推出的 EasyMall 系统,参照商城类系统原型,推出 C 端用户、消息中台、商品、订单、优惠券、支付 等业务模块,帮助大家梳理商城相关的业务;同时,也会在商城业务中使用到下述技术:

  • 分布式锁;
  • 分布式事务;
  • 搜索技术;
  • 微服务流量监控;
  • 分库分表等。

3)场景实战 #

当业务系统持续开发过程中,会遇到 各式各样的场景问题,小马哥根据工作中遇到的和帮助他人已解决的,总结了以下几点,并把解决方案和代码实战放在 EasyMall 这个系统里。

  • MySQL 百万级别数据,如何导出 Execl?
  • 线上 Java 应用触发 OOM,如何第一时间通知到开发者?
  • 如何解决雪花算法在集群环境下,生成 ID 重复问题?
  • 如何通过 MyBatis 查询千万数据,并保证内存不溢出?
  • MySQL 单表千万级数据,如何避免深分页引起的线上故障?
  • MySQL 数据库表快速初始化千万数据到 ElasticSearch?
  • ……

4)基础架构 #

每天面向业务编码,工作几年写的都是不变花样的 CRUD,开发者不知道如何对技术做提升?

相信这上面这段话是很多小伙伴的困扰,找不到一个好的方式 提升自己的基础架构能力

为此,在 EasyMall 系统中,小马哥会带着大家造很多的“轮子”,包括不限于:规约、缓存、公共、分布式 ID、数据持久层、脱敏、日志、文档 API 等组件。

另外,之前和水友群沟通,发现大家对 Java Agent 概念不是很清楚,也没有在实际场景中使用过。

在基础架构部分,会根据实际的业务场景,写一个 中台业务个性化 Java Agent,它主要做两件事情:

  • 统计调用中台接口的来源系统,比如说中台消息发送接口被用户、订单、支付等几个系统调用。
  • 采集中台系统在不同的时间窗口下被调用的频率,可以精确到接口级别。

5)设计模式 #

为什么要学习设计模式?或者说设计模式有什么好处?

设计模式主要是为了 应对代码的复杂性,让其满足开闭原则,提高代码的扩展性。避免做功能迭代时,牵一发而动全身。

同时,设计模式也是看各种底层框架的敲门砖,如果不会设计模式,点不了几个类就会被绕晕过去。

以上种种,无不彰显设计模式对于开发者的重要性。在 EasyMall 系统里,会根据不同的业务场景带大家掌握常用的设计模式,比如:单例、Builder、策略、模板方法、装饰器、动态代理等。

星球原价 98 元,对于第一批加入星球的球友们,限时优惠 30 元,最终价格 68 元。后面随着项目中的内容不断增加,星球价格也会持续增长。



注:优惠券如失效,请在公众号内回复 “星球” 领取优惠券。

代码示例 #

星球注重代码实战,这里放两段 EasyMall 中的真实代码,都是和大家工作中息息相关的技术。

1)分布式缓存封装 #

获取缓存时,防止缓存击穿、缓存穿透问题。

其中用到了分布式锁防止缓存击穿,并加上双重判断,最大可能性 减少流量请求数据库的次数;其次,使用布隆过滤器 避免缓存穿透

@Override
public <T> T safeGet(String key, Class<T> clazz, CacheLoader<T> cacheLoader, long timeout, CacheGetFilter<String> cacheGetFilter, CacheGetIfAbsent<String> cacheGetIfAbsent) {
    T result = get(key, clazz);
    // 缓存不等于空返回;缓存为空判断布隆过滤器是否存在,不存在返回空;如果前两者都不成立,通过函数判断是否返回空
    if (!CacheUtil.isNullOrBlank(result) || !cachePenetrationBloomFilter.contains(key) || Optional.ofNullable(cacheGetFilter).map(each -> each.filter(key)).orElse(false)) {
        return result;
    }
    RLock lock = redissonClient.getLock(CacheUtil.buildKey("distributed_lock_lock_get", key));
    lock.lock();
    try {
        // 双重判定锁,减轻数据库访问压力
        if (CacheUtil.isNullOrBlank(result = get(key, clazz))) {
            // 如果访问 load 数据为空,通过函数执行后置操作
            if (CacheUtil.isNullOrBlank(result = loadAndSet(key, cacheLoader, timeout, true))) {
                Optional.ofNullable(cacheGetIfAbsent).ifPresent(each -> each.execute(key));
            }
        }
    } finally {
        lock.unlock();
    }
    return result;
}

2)封装策略模式 #

封装设计模式中的策略模式,规避不同业务定义多个选择器和策略接口。

定义抽象策略接口:

public interface AbstractExecuteStrategy<REQUEST, RESPONSE> {

    /**
     * 执行策略标识
     */
    String mark();

    /**
     * 执行策略
     */
    default void execute(REQUEST requestParam) {

    }

    /**
     * 执行策略,带返回值
     */
    default RESPONSE executeResp(REQUEST requestParam) {
        return null;
    }
}

定义抽象策略选择器:

public class AbstractStrategyChoose implements ApplicationListener<ApplicationInitializingEvent> {

    /**
     * 执行策略集合
     */
    private final Map<String, AbstractExecuteStrategy> abstractExecuteStrategyMap = new HashMap<>();

    /**
     * 根据 mark 查询具体策略
     */
    public AbstractExecuteStrategy choose(String mark) {
        return Optional.ofNullable(abstractExecuteStrategyMap.get(mark)).orElseThrow(() -> new ServiceException(String.format("[%s] 策略未定义", mark)));
    }

    /**
     * 根据 mark 查询具体策略并执行
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark);
        executeStrategy.execute(requestParam);
    }

    /**
     * 根据 mark 查询具体策略并执行,带返回结果
     */
    public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark);
        return (RESPONSE) executeStrategy.executeResp(requestParam);
    }

    @Override
    public void onApplicationEvent(ApplicationInitializingEvent event) {
        Map<String, AbstractExecuteStrategy> actual = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        actual.forEach((beanName, bean) -> {
            AbstractExecuteStrategy beanExist = abstractExecuteStrategyMap.get(bean.mark());
            if (beanExist != null) {
                throw new ServiceException(String.format("[%s] Duplicate execution policy", bean.mark()));
            }
            abstractExecuteStrategyMap.put(bean.mark(), bean);
        });
    }
}

3)项目结构 #

你会学到什么 #

  1. 基于 DDD 领域驱动设计实现的商城实战代码。
  2. 商城系统业务:C 端用户、商品、订单、购物车、优惠券、支付等核心模块。
  3. 实际场景使用 SpringCloudSeataRocketMQSentinelShardingSphereElasticSearch 等主流技术。
  4. 合适的业务中完成分布式锁、分布式事务、分库分表、消息队列、服务流量监控等技术难点。
  5. 完成基础组件抽象,包括不限于:规约、缓存、公共、分布式 ID、数据持久层、脱敏、日志、文档 API 等底层 SpringBoot Starter
  6. Java Agent 流量监控开发,埋点中台接口的调用系统,以及各业务系统调用中台接口的流量记录。
  7. 设计模式代码实战,包括不限于:策略模式、Builder 模式、装饰器模式、观察者模式、适配器模式、代理模式、责任链模式等。此外,会在使用的基础上,封装出业务通用的设计模式抽象。

我列了一个 EasyMall 的思维导图:

高清大图以及最新内容可以查看:https://www.processon.com/view/link/62984d1b0e3e74603c573306 (opens new window)


Hippo-4J 番外 #

小马哥开源 Hippo-4J 动态线程池框架 (opens new window) 后,有些小伙伴表示对框架原理不是很清楚,希望能输出一些架构设计的文章。

最后决定将 Hippo-4J 架构设计的文章放到星球里,会以一个专栏的形式输出,包括不限于以下内容:

  • 动态线程池准实时变更的原理是什么?
  • 如何监控线程池以及采集运行时数据?
  • 如何完成三方框架 Dubbo、RocketMQ 等中间件线程池适配?
  • 集群环境下,单个线程池如何完成差异化配置变更?
  • 服务端如何获取线程池,在集群环境下的实例信息?

适宜人群 #

  1. 掌握 Java 基础语法,有至少 1-2 年后端开发经验,想系统深入的掌握微服务系统开发。
  2. 不满足于每天埋头搞业务和无难度 CRUD 的普通开发者。
  3. 对中间件框架、代码设计模式感兴趣,但是找不到合适的使用场景。
  4. 希望能够独立完成基础组件封装的中高级程序员。
  5. 工作中遇到了项目中列的技术难点,希望得到解决思路或提前补充相关知识。
  6. 希望掌握成体系的大型项目架构设计,在学习中获得成长。

加入星球 #

上面聊了这么多,相信加入星球能收获的内容大家都清楚了。有需要的小伙伴请扫描下面的海报二维码加入,优惠名额有限,优惠券使用完就恢复原价



注:优惠券如失效,请在公众号内回复 “星球” 领取优惠券。

加入星球后,不要忘记查看星球置顶主题,提交 EasyMall 项目申请。

最后,希望各位同学们,在学习 EasyMall 的过程中,技术能力百尺竿头,更进一步

上次更新: 9/18/2022, 9:57:31 PM