Document directory
- Using a segregated interface for the Locator
- A dynamic service locator
- Using both a locator and injection with aveon
Using a service locator
Use Service Positioner
The key benefit of a dependency injector is that it removes the dependency thatMovieLister
Class has on the concreteMovieFinderImplementation. This allows me to give listers to friends
And for them to plug in a suitable implementation for their own environment. Injection isn' t
The only way to break this dependency, another is to use a service locator.
The main advantage of dependency injection is to eliminate the dependency of movielister on the specific implementation of moviefinder. This allows me to set movielister
Give your friends and let them inject corresponding implementations according to their own environment. Injection is not the only method to remove dependencies. You can also use another method.
Remove the dependency, that is, use the service locator.
The basic idea behind a service locator is to have an object that knows how to get hold
All of the services that an application might need. So a service locator for this application
Wocould have a method that returns a movie finder when one is needed. Of course this just shifts
The burden a tad, we still have to get the locator into the Lister, resulting in the Dependencies
Of figure.
The most basic idea of a service locator is that an object locator knows how to control all services required by an application. So in the above example
A service locator of the mentioned application will use a method to return a movie finder instance as needed. Of course, this is just
We still have to get the service locator into Lister, and the result shows the following dependency.
In this case I'll use the servicelocator as a singleton registry. The Lister can then use that
Get the finder when it's instantiated.
In the following example, I will use a service locator as a single-instance registrar. Movielister can use this service locator to obtain
The instance of moviefinder.
class MovieLister...
MovieFinder finder = ServiceLocator.movieFinder();
class ServiceLocator...
public static MovieFinder movieFinder() {
return soleInstance.movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;
As with the injection approach, we have to configure the service locator. Here I'm doing it in code, but it's not hard
To use a mechanic that wocould read the appropriate data from a configuration file.
Just like the injection method, we must configure the service locator. Below I will use code to complete this function, but it is not difficult to use the mechanism to read the corresponding data from the configuration file.
Class tester...
Private void configure (){
Servicelocator. Load (New servicelocator (New colonmoviefinder ("movies1.txt ")));
}
class ServiceLocator...
public static void load(ServiceLocator arg) {
soleInstance = arg;
}
public ServiceLocator(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
Here's the test code.
The following is the test code.
Class tester...
public void testSimple() {
configure();
MovieLister lister = new MovieLister();
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West", movies[0].getTitle()); }
I 've often heard the complaint that these kinds of service locators are a bad thing because they Aren' t testable
Because you can't substitute implementations for them. Certainly you can design them badly to get into this kind
Trouble, but you don't have to. In this case the service locator instance is just a simple data holder. I can easily
Create the locator with test implementations of my services.
I often hear some complaints about how these service locators are not good because they cannot be tested because they cannot find alternative implementations. Of course, if your design is poor
But you can choose a proper design. In this example, the service locator is just such a simple data container, and I can easily use the service test implementation to create my locator.
For a more sophisticated locator I can subclass service locator and pass that subclass into the Registry's class variable.
I can change the static methods to call a method on the instance rather accessing instance variables directly. I can provide
Thread specific locators by Using thread specific storage. All of this can be done without changing clients of service locator.
For a more advanced positioner, I can use a subclass to inherit and pass the subclass to the class variable of the Register (implement a servicelocator subclass and pass it to the class variable at initialization)
Soleinstance ). I can modify the static method to call a method of the servicelocator instance instead of directly accessing the instance variable. (Not direct access
Soleinstance. moviefinder method ). I can also provide thread-related storage mechanisms to provide thread-related locators. All of these do not need to change the client's service locator.
A way to think of this is that service locator is a registry not a singleton. A singleton provides a simple way of
implementing a registry, but that implementation decision is easily changed.
One way to improve is that service locators are still registrars rather than Singleton. Singleton provides a simple way to implement the registration machine, but that implementation is easily changed.
Using a segregated interface for the LocatorIsolate service locators
One of the issues with the simple approach above, is that the movielister is dependent on the full service locator class,
Even though it only uses one service. We can reduce this by using a segregated interface. That way, instead of using
Full service locator interface, the Lister can declare just the bit of interface it needs.
The preceding simple method has a problem: movielister relies entirely on the service locator class, although it only uses a service. We can use isolated interfaces to reduce
This dependency. In that case, movielister can just declare the interface it requires, rather than using the entire service locator interface.
In this situation the provider of the Lister wocould also provide a locator interface which it needs to get hold of the finder.
In this case, the movielister provider will also provide a locator interface, and movielister needs this locator interface to control moviefinder.
public interface MovieFinderLocator {
public MovieFinder movieFinder();
The locator then needs to implement this interface to provide access to a finder.
The service locator needs to implement this interface to provide access to moviefinder.
MovieFinderLocator locator = ServiceLocator.locator();
(Interfaces used by different service providers are isolated to avoid interface pollution)
MovieFinder finder = locator.movieFinder();
public static ServiceLocator locator() {
return soleInstance;
}
public MovieFinder movieFinder() {
return movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;
You'll notice that since we want to use an interface, we can't just access the services through static methods any
More. We have to use the class to get a locator instance and then use that to get what we need.
You will find that because we use an interface, we can no longer access the service only through the static method, we must use the class to get a locator instance, let
The instance obtains the services we want.
A dynamic service locatorDynamic service Positioner The above example was static, in that the service locator class has methods for each of the services that you need.
This isn't the only way of doing it, you can also make a dynamic service locator that allows you to stash any service
You need into it and make your choices at runtime.
The above is an example of a static positioner. For every service you need, the service locator class has a corresponding method. This is not the only way to implement the service locator. You also
You can use a dynamic positioner, which allows you to register any service you need and decide which service to use at runtime.
In this case, the service locator uses a map instead of fields for each of the services, and provides generic methods
To get and load services.
In this example, the service locator uses map to replace each service field and uses a common method to obtain and locate the service.
class ServiceLocator...
private static ServiceLocator soleInstance;
public static void load(ServiceLocator arg) {
soleInstance = arg;
}
private Map services = new HashMap();
public static Object getService(String key){
return soleInstance.services.get(key);
}
public void loadService (String key, Object service) {
services.put(key, service);
}
Configuring involves loading a service with an appropriate key.
You also need to configure the service positioner to load the service object and the appropriate keywords to the positioner.
class Tester...
private void configure() {
ServiceLocator locator = new ServiceLocator();
locator.loadService("MovieFinder", new ColonMovieFinder("movies1.txt"));
ServiceLocator.load(locator);
}
I use the service by using the same key string.
I use a string with the same name as the service object class as a keyword.
class MovieLister...
MovieFinder finder = (MovieFinder) ServiceLocator.getService("MovieFinder");
On the whole I dislike this approach. Although it's certainly flexible, it's not very explicit. The only way I can
Find out how to reach a service is through textual keys. I prefer explicit methods because it's easier to find where
They are by looking at the interface definitions.
In general, I don't like this method. Although he is quite flexible, his usage is not clear. I want to locate a service with only keywords in text format.
I prefer the intuitive method, because it is easy to locate the service by viewing the interface definition.
Using both a locator and injection with aveonDependency injection and a service locator aren't necessarily mutually exclusive concepts. A good example of using
Both together is the aveon framework. aveon uses a service locator, but uses injection to tell components where
To find the locator.
Dependency injection and service positioning are not mutually exclusive concepts. A good example of their full use is the avron framework. avron uses a service locator, but it also uses an injection
To tell the component how to find the positioner.
Berin loritsch sent me this simple version of my running example using aveon.
Berin loritsch sent me a simple version of aveon in the previous example.
public class MyMovieLister implements MovieLister, Serviceable { private MovieFinder finder; public void service( ServiceManager manager ) throws ServiceException {
finder = (MovieFinder)manager.lookup("finder"); }
The service method is an example of interface injection, allowing the container to inject a service manager into mymovielister.
The service manager is an example of a service locator. In this example the lister doesn't store the manager in a field,
Instead it immediately uses it to lookup the finder, which it does store.
The service method is an example of interface injection. Allowing containers to inject the service manager into mymovielister. The service manager is an example of a service locator. In this example
Instead of storing the manager as a field, you can use it to immediately locate moviefinder and store moviefinder as a field.