Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fixed bad links due to copy-paste from cwiki-test

...

Dependency Injection

Main Article: Tapestry IoC Overview Injection

Div
stylefloat:right
titleRelated Articles
classaui-label
Content by Label
showLabelsfalse
showSpacefalse
titleRelated Articles
cqllabel = "injection" and space = currentSpace()

...

This code is for a metric that periodically counts the number of rows in a key database table. Other implementations of MetricProducer will be responsible for measuring CPU utilization, available disk space, number of requests per second, and so forth.

Code Block
java
languagejava
public class TableMetricProducer implements MetricProducer
{
  . . . 

  public void execute() 
  {
    int rowCount = . . .;
    Metric metric = new Metric("app/clients", System.currentTimeMillis(), rowCount);
    new QueueWriter().sendMetric(metric);
  }
}

...

Obviously, this code has a problem ... we're creating a new QueueWriter for each metric we write into the queue, and the QueueWriter presumably is going to open the JMS queue fresh each time, an expensive operation. Thus:

Code Block
java
languagejava
public class TableMetricProducer implements MetricProducer
{
  . . . 

  private final QueueWriter queueWriter = new QueueWriter();

  public void execute() 
  {
    int rowCount = . . .;
    Metric metric = new Metric("app/clients", System.currentTimeMillis(), rowCount);
    queueWriter.sendMetric(metric);
  }

...

Here's a more immediate problem: JMS connections are really meant to be shared, and we'll have lots of little classes collecting different metrics. So we need to make the QueueWriter shareable:

Code Block
java
languagejava
  private final QueueWriter queueWriter = QueueWriter.getInstance();

... and inside class QueueWriter:

Code Block
java
languagejava
public class QueueWriter
{
  private static QueueWriter instance;

  private QueueWriter()
  {
    ...
  }

  public static getInstance()
  {
    if (instance == null)
    {
      instance = new QueueWriter();
    }
    return instance;
  }
}

Much better! Now all the metric producers running inside all the threads can share a single QueueWriter. Oh wait ...

Code Block
java
languagejava
  public synchronized static getInstance()
  {
    if (instance == null)
    {
      instance = new QueueWriter();
    }
    return instance;
  }

...

We'll need to change TableMetricProducer to take the QueueWriter as a constructor parameter.

Code Block
java
languagejava
public class TableMetricProducer implements MetricProducer
{
  private final QueueWriter queueWriter;

  /**
   * The normal constructor.
   *
   */
  public TableMetricProducer(. . .)
  {
    this(QueueWriterImpl.getInstance(), . . .);
  }

  /**
   * Constructor used for testing.
   *
   */
  TableMetricProducer(QueueWriter queueWriter, . . .)
  {
    queueWriter = queueWriter;
    . . . 
  }

  public void execute() 
  {
    int rowCount = . . .;
    Metric metric = new Metric("app/clients", System.currentTimeMillis(), rowCount);

   queueWriter.sendMetric(metric);
  }
}

...

For comparison, lets see what the Tapestry IoC implementation would look like:

Code Block
java
languagejava
public class MonitorModule
{
  public static void bind(ServiceBinder binder)
  {
    binder.bind(QueueWriter.class, QueueWriterImpl.class);
    binder.bind(MetricScheduler.class, MetricSchedulerImpl.class);
  }

  public void contributeMetricScheduler(Configuration<MetricProducer> configuration, QueueWriter queueWriter, . . .)
  {
    configuration.add(new TableMetricProducer(queueWriter, . . .))
  }
}

...

What we are saying is that IoC techniques and discipline will lead to applications that are:

  • More testable – smaller, simpler classes; coding to interfaces allows use of mock implementations
  • More robust – smaller, simpler classes; use of final variables; thread safety baked in
  • More scalable – thread safety baked in
  • Easier to maintain – less code, simpler classes
  • Easier to extend – new features are often additions (new services, new contributions) rather than changes to existing classes

...