如何将若依框架与Spring Cloud进行微服务改造的集成?
摘要: 将若依(Ruoyi)单体架构改造为基于Spring Cloud的微服务系统,核心步骤包括:按业务域拆分模块为独立服务(如认证、系统、用户等),集成Nacos实现服务注册与配置中心,通过Spring Cloud Gateway统一路由和认证。保留若依公共模块复用工具类,使用OpenFeign实现服务间调用,并引入Sentinel保障稳定性。改造后系统具备高内聚低耦合特性,同时保持原有功能。
将若依(Ruoyi)框架与Spring Cloud进行微服务改造,核心是将若依的单体架构拆分为独立的微服务,并通过Spring Cloud生态组件实现服务注册、发现、路由、认证等微服务核心能力。以下是具体的集成思路和步骤:
一、改造前提与目标
-
现状分析
若依单体架构的核心模块:ruoyi-system
(系统管理)、ruoyi-user
(用户权限)、ruoyi-generator
(代码生成)、ruoyi-job
(定时任务)等,所有模块共享数据库和配置,服务间调用通过本地方法实现。 -
改造目标
- 拆分独立微服务,实现“高内聚低耦合”;
- 引入Spring Cloud组件实现服务注册/发现、配置中心、网关路由、统一认证等;
- 保留若依的核心功能(权限体系、前端组件、代码生成等),减少重复开发。
二、微服务拆分策略
按“业务域”拆分若依模块,核心原则:一个服务对应一个业务能力,数据独立存储。建议拆分如下:
微服务名称 | 对应若依模块 | 核心功能 |
---|---|---|
认证服务(auth) | ruoyi-security |
登录认证、Token生成、权限校验 |
系统服务(system) | ruoyi-system |
菜单管理、字典管理、参数配置 |
用户服务(user) | ruoyi-system 中的用户模块 |
用户管理、角色管理、部门管理 |
业务服务(business) | 自定义业务模块 | 如订单、商品等业务逻辑 |
网关服务(gateway) | 新增 | 路由转发、限流、认证前置 |
配置中心(config) | 新增 | 集中管理所有服务配置 |
三、核心组件集成与改造步骤
1. 基础环境搭建(Spring Cloud核心组件)
选择适配Spring Boot 2.x/3.x的Spring Cloud版本(如Alibaba Cloud 2021.x或Spring Cloud 2022.x),核心组件如下:
组件功能 | 推荐组件 | 作用说明 |
---|---|---|
服务注册/发现 | Nacos | 替代单体架构的本地调用,实现服务注册与发现 |
配置中心 | Nacos Config | 集中管理各服务配置,支持动态刷新 |
网关 | Spring Cloud Gateway | 统一入口,路由请求到对应微服务 |
服务调用 | OpenFeign | 声明式HTTP客户端,简化服务间调用 |
熔断与限流 | Sentinel | 防止服务雪崩,保护系统稳定性 |
分布式事务 | Seata | 解决跨服务事务一致性问题 |
2. 服务拆分与改造(以“系统服务”为例)
(1)保留若依核心依赖
每个微服务需引入若依的公共模块(ruoyi-common
),复用工具类、异常处理、响应格式等:
<!-- 引入若依公共模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${ruoyi.version}</version>
</dependency>
(2)集成服务注册与发现(Nacos)
在每个微服务的pom.xml
中添加Nacos依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在application.yml
中配置Nacos地址:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos服务地址
application:
name: ruoyi-system # 服务名称(关键,用于服务调用)
启动类添加@EnableDiscoveryClient
注解:
@SpringBootApplication
@EnableDiscoveryClient
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
(3)改造服务间调用(OpenFeign)
若依单体中通过@Autowired
调用本地Service,微服务中需通过OpenFeign调用其他服务接口。
例如:用户服务调用系统服务的菜单接口:
- 在用户服务中定义Feign客户端:
@FeignClient(name = "ruoyi-system") // 对应系统服务的application.name
public interface SystemFeignClient {
@GetMapping("/system/menu/getMenuList")
R<List<Menu>> getMenuList(@RequestParam("userId") Long userId);
}
- 在用户服务中注入并使用:
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private SystemFeignClient systemFeignClient;
@Override
public List<Menu> getUserMenu(Long userId) {
// 调用系统服务的接口
R<List<Menu>> result = systemFeignClient.getMenuList(userId);
return result.getData();
}
}
3. 统一配置中心(Nacos Config)
将若依单体的application.yml
配置拆分到Nacos,实现集中管理。
- 每个服务添加Nacos Config依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 创建
bootstrap.yml
(优先级高于application.yml),指定Nacos配置地址:
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml # 配置文件格式
application:
name: ruoyi-system # 对应Nacos中的配置文件名(ruoyi-system.yaml)
- 在Nacos控制台创建配置文件(如
ruoyi-system.yaml
),存放原若依中与系统服务相关的配置(数据源、MyBatis等)。
4. 网关集成(Spring Cloud Gateway)
网关作为微服务的统一入口,替代若依单体的前端直接调用后端接口的模式。
(1)搭建网关服务
- 新建网关模块(
ruoyi-gateway
),引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 配置路由规则(
application.yml
),将请求转发到对应微服务:
spring:
cloud:
gateway:
routes:
# 系统服务路由
- id: ruoyi-system
uri: lb://ruoyi-system # lb表示负载均衡,ruoyi-system是服务名
predicates:
- Path=/api/system/** # 前端请求路径前缀
filters:
- StripPrefix=1 # 去掉路径中的/api前缀,实际转发到/system/**
# 用户服务路由
- id: ruoyi-user
uri: lb://ruoyi-user
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
(2)网关层认证拦截
复用若依的Token认证逻辑,在网关层统一验证Token有效性,避免每个服务重复实现:
- 自定义网关过滤器(验证Token):
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求头中的Token(若依默认Token放在Authorization头)
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
// 2. 验证Token(复用若依的TokenUtil工具类)
if (StringUtils.isEmpty(token) || !TokenUtil.verify(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 3. 验证通过,转发请求
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0; // 过滤器执行顺序,数字越小越先执行
}
}
5. 统一认证服务(OAuth2 + JWT)
若依单体使用Shiro/Spring Security做认证,微服务下需搭建独立的认证服务(ruoyi-auth
),基于OAuth2 + JWT实现统一认证。
(1)认证服务实现
- 引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <!-- 复用若依的用户查询逻辑 -->
</dependency>
- 配置认证服务器,复用若依的用户信息:
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService; // 若依的UserDetailsService实现
// 配置JWT令牌存储
@Bean
public JwtAccessTokenConverter tokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("ruoyi-secret"); // 签名密钥
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 配置客户端信息(前端应用)
clients.inMemory()
.withClient("ruoyi-web")
.secret(passwordEncoder.encode("123456"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("all");
}
}
(2)前端改造
若依前端(Vue)的请求地址统一指向网关,登录流程改为调用认证服务获取JWT令牌:
// 原登录请求(单体):/login
// 微服务登录请求(通过网关转发到认证服务):/api/auth/oauth/token
// axios配置基础路径为网关地址
axios.defaults.baseURL = "http://localhost:8080/api";
// 登录方法
login(username, password) {
return request({
url: '/auth/oauth/token',
method: 'post',
params: {
username,
password,
grant_type: 'password',
client_id: 'ruoyi-web',
client_secret: '123456'
}
});
}
6. 分布式事务处理(Seata)
微服务间跨服务操作(如“创建订单同时扣减库存”)需要保证事务一致性,集成Seata:
- 所有微服务引入Seata依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
- 在发起分布式事务的方法上添加
@GlobalTransactional
注解:
@Service
public class OrderServiceImpl implements IOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private StorageFeignClient storageFeignClient; // 库存服务Feign客户端
@Override
@GlobalTransactional // 开启分布式事务
public void createOrder(Order order) {
// 1. 创建订单(本地事务)
orderMapper.insert(order);
// 2. 调用库存服务扣减库存(跨服务)
storageFeignClient.reduceStock(order.getProductId(), order.getCount());
}
}
四、关键注意事项
-
数据库拆分
单体若依使用单一数据库,微服务下建议按服务拆分数据库(如user_db
、system_db
),避免多服务共享数据库导致耦合。若需跨库查询,通过Feign调用其他服务接口,而非直接操作其他库。 -
权限体系适配
若依的权限基于“用户-角色-菜单”模型,微服务下需将权限数据存储在认证服务,其他服务通过Feign获取当前用户权限,或在JWT中携带权限信息(减少服务间调用)。 -
前端兼容性
若依前端组件(如表格、表单、权限指令v-hasPermi
)无需大幅改造,只需修改API请求路径为网关地址,适配JWT令牌的存储与传递(如放在Authorization
请求头)。 -
服务粒度控制
避免过度拆分(如将用户服务拆分为“用户基本信息服务”“用户角色服务”),建议初期按大业务域拆分,后期再根据性能需求细化。
五、总结
若依与Spring Cloud的微服务集成,核心是“拆分服务+集成组件+保留核心能力”:
- 按业务域拆分若依模块为独立微服务;
- 集成Nacos(注册/配置)、Gateway(网关)、OpenFeign(服务调用)等组件;
- 搭建统一认证服务,复用若依权限模型;
- 通过网关和分布式事务保证系统可用性与数据一致性。
改造后可实现服务独立部署、弹性扩展,同时保留若依的快速开发能力,适合中大型项目的架构演进。
更多推荐
所有评论(0)