基于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.**
注意事项
- 确保订单服务与商品服务都能通过依赖访问到
com.udemy.shared.command包下的类。 - 若后续其他命令/事件类出现相同异常,需同步添加到授权列表中。
- 避免盲目授权所有类(如
**),仅授权业务必需的包或类,降低安全风险。
内容的提问来源于stack exchange,提问作者Sam Fisher
相关产品推荐
相关产品推荐

