A service in the terms of annocon is a component of an application that should benefit from the features of an IoC container: Mainly the wiring with other services (dependency injection) and the configuration. An annocon service can be represented by a class or interface and can be implemented as simple POJO (plain old java object).
To define services and make them known to the container and possible clients, a central mechanism is needed. In annocon this role is PLAYED!! by a special context class. The context class has annotated methods that are responsible for the service construction at runtime.
The next example demonstrates a simple context defining exactly one service:
@Context public class BasicContext { @Service(id = "AuthenticationService") public AuthenticationService getAuthenticationService() { return new AuthenticationService(); } }
In this example two annotations have been used. The @Context annotation marks the context class itself as annocon context. The @Service annotation marks the method getAuthenticationService() as the factory method for the instantiation of a service which is named "AuthenticationService". The assigned id is used for error handling on the one hand and on the other hand for reflective access to a service.
It is now possible to create the context and get a reference to the defined service. Therefore the context class is handed in to annocon's ContextFactory which processes the class and mixes in aspects:
ContextFactory factory = new ContextFactory(); BasicContext context = (BasicContext) factory.buildContext(BasicContext.class); AuthenticationService authenticationService = context.getAuthenticationService(); authenticationService.checkPassword("admin", "access");
On the first look it could appeal that this is nothing better than directly creating an instance of the context class but there is already a subtle but important difference: The context class aspectized by annocon ensures that the authentication service is a singleton. Each call to the getAuthenticationService method returns the same instance.
This behaviour is controled by the instantiation model which is defined by the instantiationModel attribute of the @Service annotation. Besides the default singleton model it is possible to use the prototype model. In this case each call to the service method returns a new instance:
@Context public class BasicContext { @Service(id = "AuthenticationService", instantiationModel="prototype") public AuthenticationService getAuthenticationService() { return new AuthenticationService(); } }
Rather seldom a service works as 'lone wolf' and doesn't need any references to other services. But if collaboration of services is required than the context class is the right place to wire the services.
As pure java solution annocon offers the possibility to get references to other services just by calling the corresponding getter methods in the context class. This is as simple as effective:
@Context public class BasicContext { @Service(id = "AuthenticationService") public AuthenticationService getAuthenticationService() { AuthenticationService service = new AuthenticationService(); service.setUserManager(getUserManager()); return service; } @Service(id = "UserManager") public UserManager getUserManager() { return new SimpleUserManager(); } }
Note that UserManager is an interface. The implementation class can easily switched by changing the implementation of getUserManager(). The switch is transparent for the dependent services. The full source code can be found here: BasicContext, AuthenticationService, UserManager, SimpleUserManager
The wiring can become even more comfortable when the annotated meta data is used for autowiring.