将若依(Ruoyi)框架与Spring Cloud进行微服务改造,核心是将若依的单体架构拆分为独立的微服务,并通过Spring Cloud生态组件实现服务注册、发现、路由、认证等微服务核心能力。以下是具体的集成思路和步骤:

一、改造前提与目标

  1. 现状分析
    若依单体架构的核心模块:ruoyi-system(系统管理)、ruoyi-user(用户权限)、ruoyi-generator(代码生成)、ruoyi-job(定时任务)等,所有模块共享数据库和配置,服务间调用通过本地方法实现。

  2. 改造目标

    • 拆分独立微服务,实现“高内聚低耦合”;
    • 引入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调用其他服务接口。
例如:用户服务调用系统服务的菜单接口:

  1. 在用户服务中定义Feign客户端:
@FeignClient(name = "ruoyi-system")  // 对应系统服务的application.name
public interface SystemFeignClient {
    @GetMapping("/system/menu/getMenuList")
    R<List<Menu>> getMenuList(@RequestParam("userId") Long userId);
}
  1. 在用户服务中注入并使用:
@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,实现集中管理。

  1. 每个服务添加Nacos Config依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  1. 创建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)
  1. 在Nacos控制台创建配置文件(如ruoyi-system.yaml),存放原若依中与系统服务相关的配置(数据源、MyBatis等)。
4. 网关集成(Spring Cloud Gateway)

网关作为微服务的统一入口,替代若依单体的前端直接调用后端接口的模式。

(1)搭建网关服务
  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>
  1. 配置路由规则(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有效性,避免每个服务重复实现:

  1. 自定义网关过滤器(验证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)认证服务实现
  1. 引入依赖:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
    <groupId>com.ruoyi</groupId>
    <artifactId>ruoyi-common</artifactId>  <!-- 复用若依的用户查询逻辑 -->
</dependency>
  1. 配置认证服务器,复用若依的用户信息:
@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:

  1. 所有微服务引入Seata依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
  1. 在发起分布式事务的方法上添加@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());
    }
}

四、关键注意事项

  1. 数据库拆分
    单体若依使用单一数据库,微服务下建议按服务拆分数据库(如user_dbsystem_db),避免多服务共享数据库导致耦合。若需跨库查询,通过Feign调用其他服务接口,而非直接操作其他库。

  2. 权限体系适配
    若依的权限基于“用户-角色-菜单”模型,微服务下需将权限数据存储在认证服务,其他服务通过Feign获取当前用户权限,或在JWT中携带权限信息(减少服务间调用)。

  3. 前端兼容性
    若依前端组件(如表格、表单、权限指令v-hasPermi)无需大幅改造,只需修改API请求路径为网关地址,适配JWT令牌的存储与传递(如放在Authorization请求头)。

  4. 服务粒度控制
    避免过度拆分(如将用户服务拆分为“用户基本信息服务”“用户角色服务”),建议初期按大业务域拆分,后期再根据性能需求细化。

五、总结

若依与Spring Cloud的微服务集成,核心是“拆分服务+集成组件+保留核心能力”:

  1. 按业务域拆分若依模块为独立微服务;
  2. 集成Nacos(注册/配置)、Gateway(网关)、OpenFeign(服务调用)等组件;
  3. 搭建统一认证服务,复用若依权限模型;
  4. 通过网关和分布式事务保证系统可用性与数据一致性。

改造后可实现服务独立部署、弹性扩展,同时保留若依的快速开发能力,适合中大型项目的架构演进。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐