spring-boot - 处理 Axon 事件时出现 ForbiddenClassException?

标签 spring-boot xstream axon

我有基于 SpringBootSpringData JPAAxon 的沙盒应用程序微服务。 我创建了 2 个简单的微服务:订单服务和产品服务,并尝试探索 Axon Sagas。在 Saga 交易期间,我执行订单创建命令,当发生这种情况时,Saga 会发出产品保留事件。此事件在产品服务中处理,失败并显示:

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

如何解决?

订单微服务中的 Controller 代码:

@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;
}

传奇代码:

@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);
    }
}

谷歌搜索后我发现,不同的 Spring Boot 版本可以有不同的 xstream 版本,并且更相关的 xstream 会产生此异常。我将这些服务中的 Spring Boot 版本降级到 2.7.8,但这没有帮助

我的项目的 JDK 和结构可以在屏幕上看到

enter image description here

enter image description here

最佳答案

我猜您使用的是 JDK17 或更高版本,Sam。就目前情况而言,XStream 与较新的 JDK 版本不能很好地配合,因为它非常依赖反射。由于正在关闭,可能会发生异常。

遗憾的是,Axon Framework 默认使用所谓的 XStreamSerializer。将其更改为其他内容会给所有框架用户带来重大变化。因此,默认设置被卡住了。

为了在 Spring Boot 环境中解决此问题,框架会为您连接一个自定义 XStream 实例,将您的 @SpringBootApplication 注解类的包名称添加到 XStream 的安全上下文中。不过,Axon 确实会记录有关此问题的警告消息,因为强烈建议您根据要反/序列化的对象自行定义 XStream 安全上下文。

无论如何,通过采取此路线,十分之九的场景都可以用于反/序列化。但是,我假设您的 ReserveProductCommand 驻留在不同的包中。

好吧,即使不是,我们也建议您自己定义 XStream 的安全上下文。 或者,您可以通过定义 JacksonSerializer 将 Axon Framework 的 Serializer 从 XML 切换为 JSON。 特别是对于您的消息(命令、事件和查询),建议使用 JSON 的较小格式。这可以节省网络流量和存储空间。

正如您可能注意到的,我对您的 JDK 版本和包结构做出了一些假设。如果我建议的解决方案不能解决困境,请务必发表评论。

关于spring-boot - 处理 Axon 事件时出现 ForbiddenClassException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75604172/

相关文章:

java - 从数据库中检索 Spring Boot 配置

spring - 如何使 Spring Boot 默认为 application/json;charset=utf-8 而不是 application/json;charset=iso-8859-1

Java XStream Deep Copy 引发异常 ObjectAccessException

cqrs - 将事件附加到 eventstore

cqrs - 轴突框架 : Handle only events published by the same JVM instance?

spring - 带有@Audited 的基本模型

java - 如何在我的maven项目中导入FFMPEG库?

java - XStream 中没有已知类类型的注释

java - 使用 xstream 的自定义转换器

domain-driven-design - 在 CQRS 中同步查询端数据 - 不会仍然存在争用吗?