Note: This article has since been merged into the IoC documentation.

It is recommended you look there for up to date IoC info.

You have a Fantom class that does cool stuff. If it were an IoC service you could @Inject into other classes. Awesome! But how do you convert a standard Fantom class into an IoC service? This article tells you how.

What is an IoC Service?

But first, let's define just what an IoC service is...

An IoC service is just a plain old Fantom class. But is one that is created and stored by IoC. IoC may then inject this instance into other classes, or services, that require it.

To do this, IoC needs to know 2 things:

  1. How to build the service, and
  2. A unique ID to store it under.

Both of these need to be defined in your application's AppModule - the place where all IoC configuration takes place.

Note that IoC does not want an instance of your service. Instead it wants to know how to make it. That is because IoC will defer creating your service for as long as possible.

If nobody ever asks for your service, it is never created. If the service is explicitly asked for, either by you or by anther service, only then is it created.

Defining the IoC Service

Assuming you have a Fantom project set up, or are running a BedSheet web app, let's convert the const Users class (as defined in From One Thread to Another...) into an IoC service.

We can do this in two ways:

1. Add a Service Definition

defineServices() is a special static method in your AppModule which takes a single parameter of ServiceDefinitions. This is easiest way to define an IoC service; just add the type of your Fantom class:

using afIoc

const class AppModule {
    Void defineServices(RegistryBuilder bob) {
        bob.addService(Users#)
    }
}

From just the service Type, IoC then infers the following:

  1. The service can be autobuilt from a ctor, and
  2. The qualified name of the service Type is the unique ID.

The addService(...) method returns a ServiceBuilder class which lets you change the defaults. Example:

using afIoc

const class AppModule {
    Void defineServices(RegistryBuilder bob) {
        defs.add(Users#).withId("penguin").withAlias("seal")
    }
}

2. Create a builder Method

Services can also be defined by declaring a custom build method where you manually build the service yourselves:

using afIoc

const class AppModule {

    @Build
    Users buildUsers() {
        return Users()
    }
}

The method may be called anything you like and be of any scope, but it needs the @Build facet.

From the service builder method, IoC then infers the following:

  1. The service can be created by calling the builder method,
  2. The unique ID is qualified name of the method's return Type.

Service builder methods are a very powerful pattern as they give you complete control over how the service is created. Default options maybe overriden by @Build facet attributed and you can inject other IoC services as method parameters!

A more complicated example could therefore be:

@Build { serviceId="penguin"; aliases=["seal"] }
Users buildUsers(OtherService otherService) {
    users := otherService.createUsers("some config")
    users.moreInit(69)
    return users
}

Epilogue

To convert a Fantom class into am IoC service, define it in your AppModule by means of either the defineServices() method or a custom builder method.

Your service can now be injected into any other IoC service!

Have fun!

Edits

  • 31 July 2016 - Updated to use IoC 3.0.
  • 14 Nov 2013 - Original article.


Discuss