一、先搞懂:UserServer 在 IM 系统里的角色
在之前的 IM 微服务架构里,UserServer 承担 3 个核心职责:
- 用户认证:注册(用户名/手机号)、登录(用户名密码/手机验证码)、会话管理;
- 用户信息管理:头像、昵称、签名、手机号的修改与查询;
- 基础支撑:给其他服务提供用户信息(比如好友服务查好友资料、消息服务查发送者信息)。
所以设计时,必须考虑可扩展性(比如后续加第三方登录)、可测试性(比如不用真实短信也能测手机号登录)、性能(登录会话用 Redis 缓存,避免查库)。
二、核心设计:从依赖到架构,拒绝'硬编码'
1. 依赖注入:让服务更灵活(踩过坑才懂的重要性)
最开始写 UserServiceImpl 的时候,我直接在类里 new 了 DMSClient(真实短信服务),后来发现个人开发者没法申请企业短信资质,想换成模拟服务时,改了大半天代码。后来重构时,把所有外部依赖都通过构造函数注入,这才清爽了。
看核心构造函数:
UserServiceImpl( const MockSmsClient::ptr& mock_sms_client, // 短信服务(真实/模拟可替换)
const std::shared_ptr<elasticlient::Client>& es_client, // ES(用户搜索用)
const std::shared_ptr<odb::core::database>& mysql_client, // MySQL(用户数据存储)
const std::shared_ptr<sw::redis::Redis>& redis_client, // Redis(会话/验证码)
const ServiceManager::ptr& channel_manager, // 服务管理(调用文件服务等)
const std::string& file_service_name // 文件服务名称(定位服务用)
) : _es_user(std::make_shared<ESUser>(es_client)),
_mysql_user(std::make_shared<UserTable>(mysql_client)),
_redis_session(std::make_shared<Session>(redis_client)),
_redis_status(std::make_shared<Status>(redis_client)),
_redis_codes(std::make_shared<Codes>(redis_client)),
_file_service_name(file_service_name),
_mm_channels(channel_manager),
_dms_client(mock_sms_client) // 注入短信服务,而非内部 new
{
_es_user->createIndex(); // 初始化 ES 用户索引
}


