JavaEnterprise JavaPerformance Impact of Using Spring.NET Dependency Injection

Performance Impact of Using Spring.NET Dependency Injection

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Spring.NET provides Dependency Injection (DI)/Inversion of
Control (IoC) as well as several other capabilities including
Data, Messaging, etc. While DI provides a lot of flexibility, it
comes at a cost. There is some added complexity; however, the
real cost is performance.

To test the performance impact of Spring.NET DI, we need to
create a series of interfaces and concrete classes that
implement the interfaces. Then we will create two console apps
to run the tests. The first console application will be a
standard C# .NET console app without Spring.Net performing
native functions. The second console application will perform
the same set of functions, but using Spring.NET and DI. Within
these two application we will add a series of timing functions
to keep track of how long each tasks takes to run.

Interfaces

Starting off we need to create the interfaces we will need to
use in the project as listed below:

  iSimpleMath

public interface iSimpleMath
{
double Add(double a, double b);
double Subtract(double a, double b);
}

iComplexMath

public interface iComplexMath
{
double Multiply(double a, double b);
double Divide(double a, double b);
}

iCalculate

interface iCalculate
{
double Calculate(double starting);
}

These interfaces are extremely simple and the concrete classes
are just as simple.

Concrete Classes

For these tests, we need to create a couple of
interfaces/classes which we can use to judge the performance
impact. Next we have the concrete classes used to implement the
interfaces.

  ConcreteSimpleMath

class ConcreteSimpleMath : Interfaces.iSimpleMath
{
public double Add(double a, double b)
{
return a + b;
}

public double Subtract(double a, double b)
{
return a – b;
}
}

ConcreteComplexMath

class ConcreteComplexMath : Interfaces.iComplexMath
{
public double Multiply(double a, double b)
{
return a * b;
}

public double Divide(double a, double b)
{
return a / b;
}
}

ConcreteCalculate

class ConcreteCalculate : Interfaces.iCalculate
{
private Interfaces.iSimpleMath simpleMath;
private Interfaces.iComplexMath complexMath;

public ConcreteCalculate(Interfaces.iSimpleMath sMath, Interfaces.iComplexMath cMath)
{
simpleMath = sMath;
complexMath = cMath;
}

public double Calculate(double starting)
{
starting = simpleMath.Add(starting, 15);
starting = complexMath.Multiply(starting, 30);
starting = simpleMath.Subtract(starting, 5);
starting = complexMath.Divide(starting, 2);
return starting;
}
}

The first two classes ConcreteSimpleMath and
ConcreteComplexMath provide a simple implementation
of the corresponding interface. The
ConcreteCalculate class does implement the
iCalculate interface, but it also a constructor accepting
members for the iSimpleMath and
iComplexMath interfaces. The Calculate
method does perform 4 calls to the simple/complex math
functions; however, the calls are not really important as the
point is to perform a minimal amount of work.

Now that we have a series of class we can create the application. First we
can create the native .NET application. as listed below to give us some base
timing information of native .NET.

.NET Test Application

  static void Main(string[] args)
  {
     Console.WriteLine("Testing .Net");
     Console.WriteLine("Running Creating Objects");
     DateTime start = DateTime.Now;

for (double i = 0; i < 100000; i++)
{
Interfaces.iCalculate cal = new Concrete.ConcreteCalculate(new Concrete.ConcreteSimpleMath(), new Concrete.ConcreteComplexMath());
cal.Calculate(i);
}

Console.WriteLine(“Done.”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString()+”ms”);
Console.WriteLine();

Console.WriteLine(“Running Use Single Object”);
start = DateTime.Now;
Interfaces.iCalculate cal2 = new Concrete.ConcreteCalculate(new Concrete.ConcreteSimpleMath(), new Concrete.ConcreteComplexMath());

for (double i = 0; i < 100000; i++)
{
cal2.Calculate(i);
}

Console.WriteLine(“Done”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString() + “ms”);
Console.ReadLine();
}

This application performs two tests, first it will time how long it takes collectively to create a new CalculateObject, SimpleMath, ComplexMath and Perform the calculation 100,000 times. Then it will run the same test and use only a single set of objects to perform the calculation on. At the conclusion of each test it will display the time the test took in milliseconds. After running the application you should see something similar to the image below:


Figure 1 – Testing .NET Application Results

Depending on your machine configuration the actual timing information will vary. However, its important to note that the time in miliseconds is mainly intended to be used as a comparison point between native .NET and Spring.NET.

Testing Spring.NET

In testing the Spring.NET application we first need to create the spring configuration in the app.config. I’ve included the snippet from the config including this section.

  <spring>
     <context>
        <resource uri="config://spring/objects" />
     </context>
     <objects >
        <object name="SimpleMath"
              type="TestingSpringNet.Concrete.ConcreteSimpleMath,TestingSpringNet"
              singleton="false" />

<object name=”ComplexMath”
type=”TestingSpringNet.Concrete.ConcreteComplexMath,TestingSpringNet”
singleton=”false” />

<object name=”ConcreteCalculate”
type=”TestingSpringNet.Concrete.ConcreteCalculate,TestingSpringNet”
singleton=”false”>
<constructor-arg name=”sMath” ref=”SimpleMath” />
<constructor-arg name=”cMath” ref=”ComplexMath” />
</object>

<object name=”SimpleMathSingleton”
type=”TestingSpringNet.Concrete.ConcreteSimpleMath,TestingSpringNet”
singleton=”true” />

<object name=”ComplexMathSingleton”
type=”TestingSpringNet.Concrete.ConcreteComplexMath,TestingSpringNet”
singleton=”true” />

<object name=”ConcreteCalculateUsingSingletons”
type=”TestingSpringNet.Concrete.ConcreteCalculate,TestingSpringNet”
singleton=”false”>
<constructor-arg name=”sMath” ref=”SimpleMathSingleton” />
<constructor-arg name=”cMath” ref=”ComplexMathSingleton” />
</object>

<object name=”ConcreteCalculateSingleton”
type=”TestingSpringNet.Concrete.ConcreteCalculate,TestingSpringNet”
singleton=”true”>
<constructor-arg name=”sMath” ref=”SimpleMathSingleton” />
<constructor-arg name=”cMath” ref=”ComplexMathSingleton” />
</object>

</objects>
</spring>

This context defines not only SimpleMath, ComplexMath and Calculate objects for testing, it also defines several others which are used to test the timing of varying levels of injection. Next, we can jump into the testing Spring.NET application.

  static void Main(string[] args)
  {
     using (IApplicationContext ctx = ContextRegistry.GetContext())
     {
        Console.WriteLine("Testing Spring.Net");
        Console.WriteLine("Running Creating Objects");
        DateTime start = DateTime.Now;

for (double i=0; i < 100000; i++)
{
// Get a new instance of the object
Interfaces.iCalculate cal = (Interfaces.iCalculate)ctx.GetObject(“ConcreteCalculate”);
cal.Calculate(i);
}

Console.WriteLine(“Done”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString() +”ms”);
Console.WriteLine();

Console.WriteLine(“Running Use Single Object”);
start = DateTime.Now;
Interfaces.iCalculate cal2 = (Interfaces.iCalculate)ctx.GetObject(“ConcreteCalculate”);

for (double i = 0; i < 100000; i++)
{
cal2.Calculate(i);
}

Console.WriteLine(“Done”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString() + “ms”);
Console.WriteLine();

Console.WriteLine(“Running using Singletons”);
start = DateTime.Now;

for (double i = 0; i < 100000; i++)
{
Interfaces.iCalculate cal3 = (Interfaces.iCalculate)ctx.GetObject(“ConcreteCalculateUsingSingletons”);
cal3.Calculate(i);
}

Console.WriteLine(“Done”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString() + “ms”);
Console.WriteLine();

Console.WriteLine(“Running using only Singletons”);
start = DateTime.Now;

for (double i = 0; i < 100000; i++)
{
Interfaces.iCalculate cal4 = (Interfaces.iCalculate)ctx.GetObject(“ConcreteCalculateSingleton”);
cal4.Calculate(i);
}

Console.WriteLine(“Done”);
Console.WriteLine(DateTime.Now.Subtract(start).TotalMilliseconds.ToString() + “ms”);
Console.ReadLine();
}
}

This application performs 4 tests. The first two tests are the same as those performed in the native .NET application above, but performed using Spring.NET. The last two tests test the performance of using varying levels of injection. Test #3 creates a ConcreteCalculate object each time, but uses Simple and Complex math singletons. Test #4 uses ConcreteCalculate, Simple and Complex math singletons. After running this application you should see similar results to the image below:


Figure 2 – Testing Spring.NET Application Results

Review the Results

To make the review simpler, I’ve created the following table to pull in the results from the two test applications.

Test Native .Net Spring.Net
Test #1: Create Objects 15.625ms 7015.625ms
Test #2: Use Single Object 15.625ms 15.625ms
Test #3: Pass Singletons N/A 3890.625ms
Test #4: Use All Singletons N/A 156.25ms

The import test to take note of is Test #1 where both applications created an object 100,000 times. For Spring.NET this is obviously a very expensive operation compared to native .NET code. Test #2 confirms that after the object is created the performance is the same with or without Spring.NET. Test #3 and #4 illustrate that Spring.NET performs better when it is able to reuse objects. Still while reusing objects, the performance is significantly more time consuming than native .NET code.

Conclusion

Spring.NET certainly provides flexibility, however, the flexibility comes at a performance price. For many applications the performance impact is minimal. If your application creates most or all of it’s objects upon startup, then the only cost is slower application startup. On the other hand, if you need to create objects very rapidly and performance is a concern, then you probably should use another framework or minimize the use of dynamic injection. It is also important to note that as of the time of this writing, Spring.NET is in version 1.2. Future versions of the framework may have improved the performance for creating objects. The intent of this article is not to try to turn people away from using Spring.NET. However, when using Spring.NET we need to be aware of the performance cost for the added flexibility.

About the Author

Chris Bennett is with Crowe Horwath LLP in the Indianapolis office. He can be reached at chris .bennett@crowehorwath.com

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories