You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Axon的微服务处理事件时出现ForbiddenClassException的解决方法

问题

基于SpringBoot、SpringData JPA、Axon构建了一个包含订单服务与商品服务的沙箱微服务应用,用于探索Axon Saga机制。执行Saga事务中的创建订单命令时,Saga发送的商品预留命令在商品服务处理时抛出如下异常:

Exception in thread "CommandProcessor-0" com.thoughtworks.xstream.security.ForbiddenClassException: com.udemy.shared.command.ReserveProductCommand

已尝试将Spring Boot版本降级至2.7.8,但问题仍未解决,求修复方案。


相关代码

订单服务控制器代码

@PostMapping
public String createOrder(@Valid @RequestBody OrderDTO order) {
    CreateOrderCommand createOrderCommand = CreateOrderCommand.builder()
            .orderId(UUID.randomUUID().toString())
            .userId("27b95829-4f3f-4ddf-8983-151ba010e35b")
            .productId(order.getProductId())
            .quantity(order.getQuantity())
            .addressId(order.getAddressId())
            .orderStatus(OrderStatus.CREATED)
            .build();
    return commandGateway.sendAndWait(createOrderCommand);
}

命令类代码

@Builder
@Data
public class CreateOrderCommand {
    @AggregateIdentifier
    private final String orderId;
    private final String userId;
    private final String productId;
    private final int quantity;
    private String addressId;
    private final OrderStatus orderStatus;
}

@Data
@Builder
public class ReserveProductCommand {
    @AggregateIdentifier
    private String productId;
    private String orderId;
    private String userId;
    private int quantity;
}

Saga代码

@Slf4j
@Saga
public class OrdersSaga {
    @Autowired
    private transient CommandGateway commandGateway;

    @StartSaga
    @SagaEventHandler(associationProperty = "orderId")
    public void handle(OrderCreatedEvent event) {
        ReserveProductCommand reserveProductCommand = ReserveProductCommand.builder()
                .orderId(event.getOrderId())
                .productId(event.getProductId())
                .userId(event.getUserId())
                .quantity(event.getQuantity())
                .build();
        commandGateway.send(reserveProductCommand, (commandMessage, commandResultMessage) -> {
            if (commandResultMessage.isExceptional()) {
                log.error("Something went wrong during product reserve: " + commandResultMessage.exceptionResult().getMessage() );
            }
        });
        log.info("Created order command fired! Order id = " + event.getOrderId());
    }

    @SagaEventHandler(associationProperty = "orderId")
    public void handle(ProductReservedEvent event) {
        log.info("Handling product reserve event for product with id = " + event.getProductId());

    }
}

商品服务事件处理器代码

@Slf4j
@Component
public class ProductEventHandler {
    ProductsRepository repository;

    @EventHandler
    public void on(ProductReservedEvent event) {
        ProductEntity updatedProduct = repository.findByProductId(event.getProductId());
        updatedProduct.setQuantity(event.getQuantity());
        log.info("Product reserved event was applied in event handler for product with id - " + event.getProductId());
        repository.save(updatedProduct);
    }
}

项目环境

  • JDK版本:17
  • 项目结构:多模块微服务架构,订单服务与商品服务分离,共享com.udemy.shared.command包下的命令类

解决方案

该异常是XStream安全策略限制导致的:Axon Framework默认使用XStream进行命令/事件序列化,而XStream从1.4.10版本开始默认禁止序列化未显式授权的类,ReserveProductCommand属于共享命令类,需在Axon配置中添加类权限。

方法1:通过配置类自定义XStream序列化器

在商品服务的Spring配置类中添加如下配置:

import com.thoughtworks.xstream.XStream;
import org.axonframework.serialization.Serializer;
import org.axonframework.serialization.xml.XStreamSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AxonConfig {

    @Bean
    public Serializer serializer() {
        XStream xStream = new XStream();
        // 允许共享命令包下所有类,也可单独指定某类
        xStream.allowTypesByWildcard(new String[]{"com.udemy.shared.command.**"});
        // 单独指定类写法:xStream.allowTypes(new Class[]{ReserveProductCommand.class});
        return XStreamSerializer.builder().xStream(xStream).build();
    }
}

方法2:通过配置文件授权(推荐)

在商品服务的application.properties或application.yml中添加Axon配置:

application.properties

# 允许单个命令类
axon.serializer.general.xstream.allow-types=com.udemy.shared.command.ReserveProductCommand
# 或允许整个命令包
# axon.serializer.general.xstream.allow-types-by-wildcard=com.udemy.shared.command.**

application.yml

axon:
  serializer:
    general:
      xstream:
        # 允许单个命令类
        allow-types: com.udemy.shared.command.ReserveProductCommand
        # 或允许整个命令包
        # allow-types-by-wildcard: com.udemy.shared.command.**

注意事项

  1. 确保订单服务与商品服务都能通过依赖访问到com.udemy.shared.command包下的类。
  2. 若后续其他命令/事件类出现相同异常,需同步添加到授权列表中。
  3. 避免盲目授权所有类(如**),仅授权业务必需的包或类,降低安全风险。

内容的提问来源于stack exchange,提问作者Sam Fisher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:45:04