ForbiddenClassException 在处理 Axon 事件时出现?

问题描述 投票:0回答:1

我有基于

SpringBoot
SpringData JPA
Axon
的沙箱应用程序微服务。 我创建了 2 个简单的微服务:订单服务和产品服务,并尝试探索 Axon Sagas。在 Saga 交易期间,我执行订单创建命令,当它发生时,Saga 发出产品储备事件。此事件在产品服务中处理,但失败并显示:

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

如何解决?

订单微服务中的控制器代码:

@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 和结构可以在屏幕上看到

spring-boot xstream axon
1个回答
0
投票

Sam,我猜你使用的是 JDK17 或更高版本。就目前而言,XStream 不能很好地与较新的 JDK 版本一起使用,因为它非常依赖于反射。由于正在关闭,因此可能会出现异常。

可悲的是,Axon Framework 默认使用所谓的

XStreamSerializer
。将其更改为其他内容会导致所有 Framework 用户发生重大更改。因此,默认卡住了。

为了在 Spring Boot 环境中解决这个问题,框架为您连接了一个自定义

XStream
实例,将您的
@SpringBootApplication
注释类的包名称添加到 XStream 的安全上下文中。不过,Axon 确实记录了一条关于此的 WARN 消息,因为强烈建议您根据要反序列化/反序列化的对象自己定义 XStream 安全上下文。

无论如何,通过这条路线,10 个场景中有 9 个都被反序列化覆盖。但是,我假设您的

ReserveProductCommand
位于不同的包中。

好吧,即使不是,也建议您自己定义 XStream 的安全上下文。 或者,您可以通过定义

Serializer
将 Axon Framework 的
JacksonSerializer
从 XML 切换到 JSON。 特别是对于您的消息(命令、事件和查询),建议使用 JSON 的较小格式。这样可以节省网络流量和存储空间。

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

© www.soinside.com 2019 - 2024. All rights reserved.