University Multi-Tenancy Example

A runnable example application exercises multi-tenancy end to end. The university-multi-tenancy-examples demo opens courses and enrolls students for several tenants at once, and shows that each tenant keeps its own events, snapshots, projections and read models while no handler names a tenant.

The samples on the other pages are written for the documentation, so each one shows a single idea on its own. This demo wires the same features into a working application, which is the place to look for how they fit together.

See the university-multi-tenancy-examples example for the full source. Its README covers running it in memory or against a multi-context Axon Server.

How it is put together

The demo is three Maven modules, so the same domain can be configured in both styles:

Module Contents

university-multi-tenancy-core

The university domain and everything both variants share: the write slices, the statistics projection and read model, the audit log, and the tenant-scoped providers in TenantComponents.

university-multi-tenancy-declarative

The Configuration API variant. Its UniversityConfiguration registers the providers explicitly and runs either fully in memory or against Axon Server.

university-multi-tenancy-springboot

The Spring Boot variant. Its UniversityConfiguration declares the same providers as beans and lets auto-configuration do the rest. Tenants are Axon Server contexts, so this variant needs a running Axon Server.

What it demonstrates

Demo element Feature

TenantProvisioning, AxonServerTenantContextManager

The tenant lifecycle, with tenants known at startup, added at runtime, and removed again

MultiTenancyDisabledTest

Disabling multi-tenancy through axon.multitenancy.enabled=false

TenantMetadataFactory

Tenant resolution from message metadata, the default resolver’s source

TenantRejections

Refusal to resolve a tenant, identical for an unknown tenant, a removed one, and a message naming none

TenantComponents

Describing a tenant-scoped component with a TenantComponentFactory

UniversityConfiguration in both variants

Registering providers, declaratively and as Spring beans

ProviderAmbiguityGuardrail

One provider per component type, with a second provider for the same type refused at configuration time

EnrollStudentCommandHandler

Tenant-aware command handling, with the course sourced from and appended to the command’s tenant

EventStorageOutcome

Per-tenant event storage, with the same course identifier full in one tenant, and still open in another

EnrollStudentCommandHandler.State, TenantSnapshots

Per-tenant snapshots, stored in and read from the snapshot store of the entity’s own tenant

CourseStatisticsProjection

Tenant-aware event processing, one processor projecting every tenant’s events into that tenant’s own read model

ReadModelWrites

An idempotent projection, deriving statistics from the identifiers in the event so a redelivery changes nothing

UniversityConfiguration in both variants

The processor restart timeout, registered at its default so the knob is visible

TenantStatisticsQueryHandler

Tenant-aware query handling, reading back only the querying tenant’s data

StatisticsSubscription

Tenant-aware subscription queries, where an update reaches only the subscriptions of the tenant it was emitted for