2
votes

Edit: Found a solution, I will update this post


Edit 2: The problem was that I defined my Commands and Events inside the src folder of my first and second microservice. The first microservice shot a com.myApplication.PaymentManagementService.commands.ApproveOrderCommand-command, while the command handler in the second microservice expected a com.myApplication.OrderManagementService.commands.ApproveOrderCommand-command.

I fixed the redundancy by lifting the commands and events a few hierarchy levels into a common api-folder that both services can access. Now the second micoservice expects a com.myApplication.api.commands.ApproveOrderCommand, that the first microservice shoots.

That solution may sound trivial to some, but since this is not described anywhere in the documentation and I didn't expect the name of the path to be relevant in handling the commands and events, you have to figure that out first.


Original post:

I'm currently implementing a distributed command bus with spring cloud. I followed the below example exactly, but I'm getting the following issues in both of my (Client-)Microservices.

https://docs.axoniq.io/reference-guide/v/master/extensions/spring-cloud

1. Could not auto-wire. There is more than one Bean of "Registration" type.

Screenshot 1

2. Cannot find a bean with the qualifier "localSegment", even though I'm using Spring Auto Configuration.

Screenshot 2

I can start both the client-applications (this one and the other microservice) nevertheless.

But:

I can't send a command from the first Microservice to the second Microservice, the following error appears:

org.axonframework.commandhandling.NoHandlerForCommandException: No node known to accept [com.myApplication.PaymentManagementService.commands.CheckPaymentCommand]

Both microservices are registered to my eureka server.

In the first Microservice, I produce a command over a REST Endpoint, the Command fires outside of an Aggegrate (via commandGateway.send()).

In the second Microservice, I want to receive the command:

@Component
public class TestCommandHandler {

    @CommandHandler
    public void handle(ApproveOrderCommand command){
        System.out.println("Command delivered!");
    }

}

Is there anything wrong with my dependencies or application properties? Do I have to setup a saga for this to work?

One of my poms:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myApplication</groupId>
    <artifactId>PaymentManagementService</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>PaymentManagementService</name>
    <description>Demo project for Spring Boot</description>
    
<properties>
    <java.version>11</java.version>
    <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>2.3.5.RELEASE</version>
    </dependency>
    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

    <!-- Axon -->
    <dependency>
        <groupId>org.axonframework</groupId>
        <artifactId>axon-spring-boot-starter</artifactId>
        <version>4.4.5</version>
        <!--
        <exclusions>
            <exclusion>
                <groupId>org.axonframework</groupId>
                <artifactId>axon-server-connector</artifactId>
            </exclusion>
        </exclusions>
        -->
        </dependency>

        <dependency>
            <groupId>org.axonframework</groupId>
            <artifactId>axon-spring-boot-autoconfigure</artifactId>
            <version>4.4.5</version>
        </dependency>

    <!-- Spring Cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    <dependency>
        <groupId>org.axonframework.extensions.springcloud</groupId>
        <artifactId>axon-springcloud-spring-boot-starter</artifactId>
        <version>4.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter</artifactId>
        <version>2.2.6.RELEASE</version>
    </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    </project>

application.properties of Microservice 1

Properties_Microservice_1

application.properties of Microservice 2

Properties_Microservice_2

1
Hi Jan, I am glad you found the answer. Just to expand a bit on that, Axon uses the full qualified name of the class as the 'name' of it, which means the package name is considered. Thanks for pointing out this is not documented, I will have a look at the docs and make sure it is included there.Lucas Campos

1 Answers

1
votes

I'm glad that you found out the solution by yourself. Hope that you discovered our sample project https://github.com/AxonFramework/extension-springcloud-sample . This is a good starting point. It also contain some indication on dependency and version that your project should have. We also have the refguide that is a must read https://docs.axoniq.io/reference-guide/extensions/spring-cloud

Looking at your pom file is not clear to me if you are or you are not using axon server. If not, I can suggest to uncomment the exclusion of axon-server-connector dependency.