1. RuoYi-Cloud微服务架构全景解析
第一次接触RuoYi-Cloud时,我被它"开箱即用"的设计理念惊艳到了。这个基于Spring Cloud Alibaba的微服务脚手架,就像乐高积木一样把企业级开发需要的核心模块都准备好了。先来看它的技术栈组成:
- 服务网关:Spring Cloud Gateway作为流量入口,比Zuul性能提升50%以上
- 服务注册:Nacos同时承担服务发现和配置中心双重角色
- 容错保护:Sentinel实现秒级熔断,我在压力测试时成功拦截了90%的雪崩风险
- 远程调用:Feign+Ribbon的组合拳,内部服务调用就像本地方法一样简单
实际部署时会发现,RuoYi-Cloud的模块划分非常符合DDD思想。比如把权限管理独立为auth服务,代码生成器作为gen服务,这种设计让系统边界特别清晰。记得第一次启动所有服务时,看着Nacos控制台上陆续亮起的8个服务节点,那种成就感至今难忘。
2. 十分钟快速搭建开发环境
去年帮团队搭建RuoYi-Cloud环境时,我整理了一套最简安装方案。以下是经过20+次实践验证的必备清单:
基础环境(必须严格匹配版本):
# JDK java -version # 要求1.8+,推荐OpenJDK 11 # Redis redis-server --version # 5.0+ # Node.js node -v # 12.0+Nacos配置技巧: 修改conf/application.properties开启MySQL持久化:
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?useSSL=false db.user=root db.password=yourpassword启动时加参数解决集群时间同步问题:
sh startup.sh -m standalone -Dnacos.core.auth.enabled=trueSentinel控制台的隐藏配置: 在application.yml中添加这些配置可以开启登录认证:
auth: enabled: true username: admin password: sentinel@123
3. 网关配置的实战心得
网关是微服务的守门人,RuoYi-Gateway的配置文件中藏着几个关键技巧:
spring: cloud: gateway: discovery: locator: enabled: true # 开启服务自动发现 routes: - id: custom-service uri: lb://custom-service predicates: - Path=/api/custom/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒10个令牌 redis-rate-limiter.burstCapacity: 20 # 突发20个请求我在电商项目中就栽过跟头:没有配置限流过滤器,促销活动时网关直接被流量打挂。后来加入Redis分布式限流后,系统稳定性提升明显。另外建议一定要开启Swagger聚合功能,这样所有微服务的API文档都能通过网关统一访问。
4. 鉴权体系的深度定制
RuoYi的JWT鉴权设计得很巧妙,但实际使用中我发现三个需要优化的点:
令牌刷新机制:默认的token过期后需要重新登录,可以增加refresh token逻辑:
// 在TokenService中添加方法 public String refreshToken(String refreshToken) { Claims claims = parseToken(refreshToken); if (claims.getExpiration().before(new Date())) { throw new RuntimeException("refreshToken已过期"); } return createToken(claims.getSubject()); }内部服务鉴权强化:除了检查from-source=inner头,我们还增加了服务白名单验证:
@Aspect public class InnerAuthAspect { @Before("@annotation(innerAuth)") public void doBefore(InnerAuth innerAuth) { String serviceId = ServletUtils.getRequest().getHeader("X-Service-Id"); if (!Arrays.asList("system-service","auth-service").contains(serviceId)) { throw new RuntimeException("非法服务调用"); } } }权限缓存优化:原生实现每次请求都查数据库,我们改用Redis缓存权限规则,QPS从200提升到2000+。
5. 代码生成器的进阶玩法
RuoYi的代码生成器能节省80%的CRUD工作量,但很多人只用了基础功能。分享几个高阶技巧:
模板定制:复制resources/templates目录下的vm文件,可以自定义生成代码风格。我团队就基于MyBatis-Plus模板改造,生成的Mapper直接支持批量操作。
多表关联生成:在生成配置界面勾选"关联查询",然后配置表关系:
-- 在生成配置SQL中添加 SELECT a.*, b.department_name FROM sys_employee a LEFT JOIN sys_department b ON a.dept_id = b.id前端组件扩展:在gen目录下添加自定义vue组件,生成时会自动识别。我们封装了富文本编辑器组件后,所有包含content字段的表单都会自动使用。
6. 自定义微服务实战指南
给系统添加一个订单服务,完整流程如下:
创建maven模块:
<!-- 在父pom中添加 --> <module>ruoyi-order</module>复制基础结构:参照system模块,需要保留:
- 启动类上的@EnableDiscoveryClient
- application.yml中的nacos配置
- MyBatis扫描路径
网关路由配置:
- id: ruoyi-order uri: lb://ruoyi-order predicates: - Path=/order/** filters: - StripPrefix=1数据库隔离建议:新建单独的order数据库,避免与系统表混用。跨库查询通过Feign调用system服务实现。
7. 性能调优实战记录
线上环境遇到过几次性能问题,总结出这些关键参数:
Feign超时配置:
feign: client: config: default: connectTimeout: 3000 readTimeout: 10000Sentinel规则持久化:配置Nacos数据源后,规则修改会自动同步:
@PostConstruct public void init() { NacosDataSource ds = new NacosDataSource( "127.0.0.1:8848", "DEFAULT_GROUP", "sentinel-ruoyi", new Converter<String, List<FlowRule>>() {...}); FlowRuleManager.register2Property(ds.getProperty()); }Redis缓存优化:采用Redisson客户端,比Lettuce节省30%内存:
@Bean public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer() .setAddress("redis://127.0.0.1:6379") .setConnectionPoolSize(32); return Redisson.create(config); }
8. 常见问题解决手册
Nacos连接失败:检查8848端口是否开放,新版Nacos需要额外开放9848/9849端口
Sentinel不生效:确保所有服务添加了spring-cloud-starter-alibaba-sentinel依赖
代码生成乱码:修改vm模板文件编码为UTF-8,IDEA设置中关闭"Transparent native-to-ascii conversion"
前端跨域问题:在网关添加CORS配置:
@Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); }Redis序列化异常:自定义配置Jackson2JsonRedisSerializer:
@Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; }