This guide takes you through the steps needed to set up a simple Axon 2 based architecture in 7 simple steps. But before you get started, you might want to create new project in your IDE. In this guide, you’ll need the axon-core and axon-test modules, as well as their dependencies. You can add them as Maven dependencies, or in the full download, which contains everything you need.

1 Domain Modeling

Unlike many other frameworks, Axon is not built to “get you started quickly”. It’s built to keep you going for a long time. But since you’re probably eager to find out how Axon works out for you, we’ll keep this one short.

Before starting to code your first Aggregate, you’ll need to identify what the actual aggregate is. This is generally not a one-shot bulls eye story. It’s trying, failing, trying, failing, succeeding, finding out you failed again, … well, you get the point. Domain Modeling is an iterative process, where new insights need to be constantly used to refactor the model.

In this quickstart, we’re keeping it short. The domain modeling, failure, succeeding, etc. has been done for you, and the result is that we need only a single aggregate: The ToDoItem. And this ToDoItem allows us to keep track of things we need, uh, to do.

To Do Item

CreateToDoItemCommand

ToDoIItemCreatedEvent

MarkCompletedCommand

ToDoItemCompletedEvent

Note how you can use a UML-like definition of your aggregate. The first level items are the commands you can execute on a ToDoItem. The second level items are the Events that are caused by these Commands. All terms used here must be understood (or better, defined) by the product owner. If they’re not, you’re most likely making a mistake.

A tip when doing domain modeling with a product owner: when modeling aggregates, define in terms of what you can do with them. Not in terms of the data they store. Once you catch the behavior of a domain concepts, it’s much easier to find the data you need. If you have only the data, you’re still nowhere.

Since this is an mission critical application, that requires heavy auditing capabilities and extreme performance, we decide to use Event Sourcing. A real no-brainer in this case…

Note that the @TargetAggregateIdentifier annotation is not always necessary. When using a distributed command bus, or the disruptor command bus, this annotation marks the field that identifies the aggregate to be invoked. Axon uses that information to route commands to the correct destination.

Code duplication? Yes, in this case the Command and Event are almost identical. In practice, they tend to diverge more, as the models are in general more complex than this one.
If you really hate duplication so much that the explicitness isn’t even worth it, rest assured. In Axon 2 it is possible to use a single object as both the Command and the Event. But you’re warned! One day, you’ll find out that they’re actually not the same… Therefore, we’ll stick to separate classes in this guide.

Note the @TargetAggregateIdentifier annotation on the todoId field. Axon needs this annotation to find the correct aggregate instance the Command targets. We’ll dive deeper into this one on step 4 and step 5.

3 Create test scenarios

One of the big advantages of using explicit Command and Event objects, is that they can be used to describe the Aggregate’s API using functional terms. As an effect, it is possible to define the test scenarios using these same terms. Since it’s all functional, you can refactor at will, with limited risk of needing to change the tests.

Let’s create such a scenario. And yes, we don’t even have an implementation yet!

First, we need to create a Test Fixture for our aggregate-to-create. I’ll be using JUnit as test framework, but you can choose any framework you like.

After fixing all the imports, one error remains: ToDoItem cannot be found. That makes sense, as we didn’t create that class yet. I’m sure your IDE has a shortcut/quickfix to create the class on the fly. Make sure it extends AbstractAnnotatedAggregateRoot, which we will further discuss in step 4.

Your aggregate will look as follows:

public class ToDoItem extends AbstractAnnotatedAggregateRoot {
}

The test fixture will automatically set up a basic infrastructure to execute the tests. For now, this infrastructure suits our needs. This means we can start writing the scenarios.

4 Implement the Aggregate

When running the test, we get a NoHandlerForCommandException: No handler was subscribed to command [your command here…]. That makes sense, because there is no aggregate that can deal with that command. Let’s implement the ToDoItem, step by step.

First, we create a Command Handler for the CreateToDoItem. Since we want this Command to create a new instance of a ToDoItem, we create a Constructor, which we annotated with @CommandHandler. The apply() method tells Axon that we want to apply this Event to the aggregate, and have it stored, and published to other components.

When we run the tests again, we get another exception: IncompatibleAggregateException: The aggregate [ToDoItem] doesn’t provide a no-arg constructor.
Easy, let’s create a no-arg constructor then. Axon uses the no-arg constructor by default to create uninitialized aggregate instances. Check out the reference guide for ways to change that.

When you run the tests again, more bad news. The tests fails “normally”, stating that no Events have been published. Beneath the table, there is a possible explanation: IncompatibleAggregateException: The aggregate class [ToDoItem] does not specify an Identifier

We need to annotate the field containing the Aggregate identifier with @AggregateIdentifier. That fields doesn’t exist yet, so we’ll create it. We’ll also create an Event Handler that sets the value of the identifier when the Aggregate is created.

Now, run the test again… you should see a green light now! Hurrah. Well, only one of the tests passes, the other fails with a familiar exception. Let’s go fix it.

This time, we want to add a Command Handler that acts on an existing aggregate. Remember we annotated the Commands with @TargetAggregateIdentifier? That tells Axon which Aggregate instance to load. So all that remains is to implement the method (not a constructor, this time).

If you run the application, you won’t see much. But the Event Store did store the Events. You should see an events directory created, with a number of files (one for each time you ran the application). If you open the file (as a text file), you’ll find an XML representation of each of the Events.

The first tag is needed only once, regardless of the number of Event Handler beans you register. It tells Axon to automatically check all beans in the Application Context for @EventHandler and @CommandHandler annotations. This works very nicely in combination with Spring’s component scanning capability.

The second tags simply creates an instance of the handler. Axon will detect the annotations and do the necessary.

7 Wrapping up…

Although we only have a very basic application, we’ve used the majority of building blocks. To get this running in a real application, you might need to configure a transaction manager on the Command Bus and a transactional Event Store, such as the JpaEventStore.

You also might want to read about Sagas in the reference guide. Once applications become bigger, and multiple Aggregates need to work together to accomplish a task, the Saga will help coordinate tasks between them.

Meanwhile, if you have any questions, don’t hesitate to contact us for help. If you really want a kick-start, visit one of the Axon training sessions, hosted by Trifork.

8 Migrating from Axon 1.x

The API’s of Axon 1.x are different from those in Axon 2. To migrate, you’ll need to make changes to the code, and to convert the Event Store to the new (better performing) format.
Check out the migration guide for a walk-through of the changes you need to make.