Forms of dependency Injection

Source: Internet
Author: User
Document directory
  • Constructor injection with picocontainer
  • Setter injection with spring
  • Interface Injection
[From: http://www.martinfowler.com/articles/injection.html]

Forms of dependency Injection

The basic idea of the dependency injection is to have a separate object, an attacker, that populates a field in the Lister class with an appropriate implementation for the finder interface, resulting in a dependency dimo-along the lines of Figure 2

Figure 2: The dependencies for a dependency Injector

There are three main styles of dependency injection. the names I'm using for them are constructor injection, setter injection, and interface injection. if you read about this stuff in the current discussions about inversion of control you'll hear these referred to as type 1 IOC (interface injection), Type 2 IOC (setter injection) and type 3 IOC (constructor injection ). I find numeric names rather hard to remember, which is why I 've used the names I have here.

Constructor injection with picocontainer

I'll start with showing how this injection is done using a lightweight container called picocontainer. i'm starting here primarily because several of my colleagues at thoughtworks are very active in the development of picocontainer (yes, it's a sort of sort ate nepotism .)

Picocontainer uses a constructor to decide how to inject a finder implementation into the Lister class. For this to work, the movie Lister class needs to declare a constructor that has des everything it needs injected.

class MovieLister...public MovieLister(MovieFinder finder) {this.finder = finder;}

The Finder itself will also be managed by the pico container, and as such will have the filename of the text file injected into it by the container.

class ColonMovieFinder...public ColonMovieFinder(String filename) {this.filename = filename;}

The Pico container then needs to be told which implementation class to associate with each interface, and which string to inject into the finder.

    private MutablePicoContainer configureContainer() {MutablePicoContainer pico = new DefaultPicoContainer();Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};pico.registerComponentImplementation(MovieFinder.class, ColonMovieFinder.class, finderParams);pico.registerComponentImplementation(MovieLister.class);return pico;}

This configuration code is typically set up in a different class. for our example, each friend who uses my Lister might write the appropriate configuration code in some setup class of their own. of course it's common to hold this kind of configuration information in separate config files. you can write a class to read a config file and set up the container appropriately. although picocontainer doesn't contain this functionality itself, there is a closely related project called nanocontainer that provides the appropriate wrappers to allow you to have xml configuration files. such a nano container will parse the XML and then configure an underlying Pico container. the philosophy of the project is to separate the config file format from the underlying mechanic.

To use the container you write code something like this.

    public void testWithPico() {MutablePicoContainer pico = configureContainer();MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class);Movie[] movies = lister.moviesDirectedBy("Sergio Leone");assertEquals("Once Upon a Time in the West", movies[0].getTitle());}

Although in this example I 've used constructor injection, picocontainer also supports setter injection, although its developers do prefer constructor injection.

Setter injection with spring

The Spring framework is a wide ranging framework for Enterprise Java development. it includes des into action layers for transactions, Persistence frameworks, web application development and JDBC. like picocontainer it supports both constructor and setter injection, but its developers tend to prefer setter injection-which makes it an appropriate choice for this example.

To get my movie Lister to accept the injection I define a setting method for that service

class MovieLister...private MovieFinder finder;public void setFinder(MovieFinder finder) {this.finder = finder;}

Similarly I define a setter for the filename.

class ColonMovieFinder...public void setFilename(String filename) {this.filename = filename;}

The third step is to set up the configuration for the files. Spring supports configuration through XML files and also through code, but XML is the expected way to do it.

    <beans><bean id="MovieLister" class="spring.MovieLister"><property name="finder"><ref local="MovieFinder"/></property></bean><bean id="MovieFinder" class="spring.ColonMovieFinder"><property name="filename"><value>movies1.txt</value></property></bean></beans>

The test then looks like this.

    public void testWithSpring() throws Exception {ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");MovieLister lister = (MovieLister) ctx.getBean("MovieLister");Movie[] movies = lister.moviesDirectedBy("Sergio Leone");assertEquals("Once Upon a Time in the West", movies[0].getTitle());}

Interface Injection

The third injection technique is to define and use interfaces for the injection. aveon is an example of a framework that uses this technique in places. i'll talk a bit more about that later, but in this case I'm going to use it with some simple sample code.

With this technique I begin by defining an interface that I'll use to perform the injection through. Here's the interface for injecting a movie finder into an object.

public interface InjectFinder {void injectFinder(MovieFinder finder);}

This interface wocould be defined by whoever provides the moviefinder interface. It needs to be implemented by any class that wants to use a finder, such as the Lister.

class MovieLister implements InjectFinder...public void injectFinder(MovieFinder finder) {this.finder = finder;}

I use a similar approach to inject the filename into the finder implementation.

public interface InjectFinderFilename {void injectFilename (String filename);}
class ColonMovieFinder implements MovieFinder, InjectFinderFilename......public void injectFilename(String filename) {this.filename = filename;}

Then, as usual, I need some configuration code to wire up the implementations. for simplicity's sake I'll do it in code.

class Tester...private Container container;private void configureContainer() {container = new Container();registerComponents();registerInjectors();container.start();}

This configuration has two stages, registering components through lookup keys is pretty similar to the other examples.

class Tester...private void registerComponents() {container.registerComponent("MovieLister", MovieLister.class);container.registerComponent("MovieFinder", ColonMovieFinder.class);}

A new step is to register the injectors that will inject the dependent components. each Injection Interface needs some code to inject the dependent object. here I do this by registering injector objects with the container. each injector object implements the injector interface.

class Tester...private void registerInjectors() {container.registerInjector(InjectFinder.class, container.lookup("MovieFinder"));container.registerInjector(InjectFinderFilename.class, new FinderFilenameInjector());}
public interface Injector {public void inject(Object target);}

When the dependent is a class written for this container, it makes sense for the component to implement the injector interface itself, as I do here with the movie finder. for generic classes, such as the string, I use an inner class within the configuration code.

class ColonMovieFinder implements Injector......public void inject(Object target) {((InjectFinder) target).injectFinder(this);}
class Tester...public static class FinderFilenameInjector implements Injector {public void inject(Object target) {((InjectFinderFilename)target).injectFilename("movies1.txt");}}

The tests then use the container.

class IfaceTester...public void testIface() {configureContainer();MovieLister lister = (MovieLister)container.lookup("MovieLister");Movie[] movies = lister.moviesDirectedBy("Sergio Leone");assertEquals("Once Upon a Time in the West", movies[0].getTitle());}

The container uses the declared injection interfaces to figure out the dependencies and the injectors to inject the correct dependents. (The specific iner implementation I did here isn't important to the technique, and I won't show it because you 'd only laugh .)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.