Spring: a foundation block for Java programming

Preamble

I want to clarify this article comes from a question I had during a consultant job for a local software company. They needed some updates on the “real world” before diving in a new project. When I introduced the DI/IoC pattern with Spring, they raised their eyebrows and asked “Is it worth it?”. Keep in mind their team was maintaining a software originally built in the early 2000s.
Note: if you’re a software engineering veteran, you might ask yourself if there really is someone out there not using Spring, and the answer is: you can’t imagine how many.

I could end it up here and say “It is”, but I think one of the major obstacles people find when adopting a technology that changes they way you program is motivation. If the motivation is high and understood, people will simply go for it without further ado.

But the benefits of a design pattern are not like a new reporting library. The benefits are subtle and show up in the long term.

What I’d like to do here is guide you through the motivations you need to adopt Spring as a foundation item of your projects, even the simplest.

This article won’t dig into incredible finding or things you didn’t know if you’re a Spring aficionado as it’s dedicated to the people who don’t know anything about Spring and are interested in learning about it.

DI/IoC

Spring is a robust, powerful implementation of the Dependency Injection pattern.

In the Dependency injection pattern, classes should just declare what dependencies are required for them to work, but should not express how they should be instantiated or which implementation should be used.
The class has to know about the “contract” of its dependencies, a “recipe” of how methods should be invoked. In Java, they typically are interfaces.
When a class with dependencies is instantiated, an injector will take care to resolve the dependencies and fulfill the contracts. Giving up control on the instantiation of these dependencies implements the Inversion of Control pattern.

Why all this mess?

This is probably what those guys thought. So let me explain some very practical advantages of using this pattern.

Implementation swapping: this is one of the most immediate aspects of DI. As long as the contract does not reveal any implementation details, you can have different implementations ready to be used. Which one is chosen depends on configuration factors, not the code using the contract.
There are several basic scenarios of this I personally experienced, such as:

  • Data sources. Whether it’s database or files or streams, you want to be free to use what works best for you when you’re in development and not be bound to a choice when you want to switch to another service, even in production.
  • Logging. If you’ve set up a sophisticated, centralized, cluster wide logging for your application, it turns into a major obstacle when you’re in development phase, when your Log4J could do all the work. Moreover, enterprise software logging is something you might want to switch to or change as your software progresses.
  • Notifications. Oh God, you don’t want to be overflowed with stupid notification emails caused by your QA team on a staging environment, right? Then you be better have a mock implementation of them. Also, mailing services can be something that you might want to change as time passes. I personally changed 3 API controlled mailing services in 3 years.
  • Mocking. Sometimes you can’t really have all of your flows running in development because some of them depend on other software you can’t hit from your desktop. What you can do is putting your correct implementation on the side and build a mock version of it, so that you can still do whatever you need to do.
  • Customization. This sucks but it happens. Sometimes your software needs some adjustments for one specific customer. Being able to swap which implementation to use based on a configuration file prevents a lot of troubles.

Isolation of technicalities / blackboxing: if a service you’re working on has to be injected in classes you do not control and will compete with other services implementing the same contract, then you need to make sure it doesn’t require or produce any implementation specific data item. By doing so, you’re literally freeing the calling classes from the technical knowledge of specific implementations. This strong segmentation simplifies the software itself, and everybody else’s work.
While this is a good practice in general, it’s strongly enforced while using IoC/DI. After all, design patterns are not just a way to achieve a result, but also a way to improve the rest of your coding routine.

Instantiation control: while good diligence can lead to proper instantiation control, a good factory pattern helps a lot. Since dependency injection can  only happen (with some exceptions) if objects are created using a factory, the factory has complete control on how they are created and when. Singletons and preemptive creation, for example, can be dealt with a simple configuration file. Moreover, if the use of the IoC pattern spreads throughout the whole software (as it should), you can decide to extend the factory capabilities to introduce unusual creation logic, such as creating no more than X number of instances, or keeping track of them.

Testing: again, good diligence vs enforcement. When you’re creating unit tests, having sharply defined services improves your testing habits. Moreover, being able to mock some other services allows you to test the most intricate routines you would generally discard as “whatever”.

More advantages are then brought in when dealing with the specifics of Spring framework.

The Spring Framework

I’m really not going to tell you the story of the glorious Spring Framework. Enough said it’s the most reputable implementation of DI for Java and a de facto industry standard.
The framework evolved over time, introducing more and more features to improve the productivity of developers, opting for a more “convention over configuration” approach.

This is not rocket science, so a good guided example is way more exciting than all this talking.

A lightning fast example

This example is pretty dumb, but should expose the very core concept. You can access the full source code here.

Two key elements you will use are:

  • the beans. the classes Spring is going build for you and inject where they need to go;
  • the context. It is where the knowledge of what’s available and what’s instantiated resides and therefore holds the capability of building beans.

The context is initiated by providing a configuration. There are multiple ways to do it, but the one I still like best is the classic beans.xml configuration file. If you’re not going to hot swap it, placing it in the classpath is a good way to go.
The same file will hold details on how to build some of the beans, by introducing entries like:

<bean id="iNotifier" class="com.simonepezzano.lessons.springfundamentals.spring1.notifiers.impl.ConsoleNotifier"/>

What this does is informing the spring context that when a “iNotifier” ID is requested, it needs to return a ConsoleNotifier instance. If the context already created one, it will return it because beans are singletons per default. If it hasn’t, it will create a new one. By changing the class attribute, I can use any implementation.

Of course, to allow other classes to use ConsoleNotifier without knowing it, ConsoleNotifier will need to implement an interface so that the dependency consumer will only know about the interface.

Example:

public interface INotifier {

    /**
     * Notifies a message
     * @param message the message
     */
    void notifyMessage(String message);

    /**
     * Notifies an checkpoint
     */
    void notifyCheckpoint();

    /**
     * Notifies an error
     * @param e the exception
     */
    void notifyError(Exception e);
}
public class ConsoleNotifier implements INotifier {

    public void notifyMessage(String message) {
        System.out.println(message);
    }

    public void notifyCheckpoint() {
        System.out.println("Checkpoint "+new Date());
    }

    public void notifyError(Exception e) {
        e.printStackTrace();
    }
}

You can implement as many notifiers as you want and turn them on and off by using the configuration file, as long as they implement the INotifier interface.

To inject the dependency where it has to be, there are -again- many ways, but the one that best combines simplicity and effectiveness for this case is annotations.

@Component  ("process")
public class UselessProcess implements Runnable {

    /**
     * The iNotifier dependency. You can find out which implementation is going to be used by
     * looking a the beans.xml file.
     * by convention, the name of the instance needs to match the ID defined in the beans configuration file.
     */
    @Autowired
    INotifier iNotifier;

    public void run() {
        /*
         * For 5 times...
         */
        for(int i=0;i<5;i++){
            // Send a notification message
            iNotifier.notifyMessage("Running message "+i);
            // Every time i is even, send a checkpoint
            if((i%2)==0)
                iNotifier.notifyCheckpoint();
            // Wait a bit
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                iNotifier.notifyError(e);
            }
        }
    }
}

Let’s start with the injection. By adding the @Autowired annotation to my INotifier instance, I’m telling Spring to inject the right dependency for this object. The type will be ignored, the only thing that matters is the name of the instance that needs to match the ID we declared in our beans.xml file.

Another interesting item is I added the @Component(“process”) annotation to the class declaration.
Two facts:

  • I will repeat it once more. If I want Spring to do his dependency injection game, the class where the dependencies are injected needs to be created by the Spring factory as well.
  • Since I’m not interested in centralizing the configuration of this bean, I’m declaring “this is a bean that will respond to the “process” ID.

If I want to have this @Component magic to work, I will need to add 2 instructions to my beans.xml file like so:

<context:annotation-config />
<context:component-scan base-package="com.simonepezzano.lessons.springfundamentals.spring1.processes"/>

Where I substantially tell the engine to look for beans starting from that package.

Finally, to get everything started, we need to have at least our context running and instantiate our first bean:

       /**
         * We create a context using 'beans.xml' as constructor's manual
         */
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        /**
         * Obtaining a process object is simple. "process" is not defined as a bean in beans.xml but it's
         * annotated. Being a Runnable, we don't even know what class implements it.
         */
        Runnable process = (Runnable) context.getBean("process");
        process.run();

You can access the full code of the example on my GitHub account.

The obvious

Now that you can see how it works with real code, you can tell it’s really easy to use, and it has to be because adoption means that it will impact all over your software and company departments.

The obvious advantages are the ones we previously mentioned while talking about DI. Strong code encapsulation/blackboxing, reusability, “swappability”, logical separation of business logic and technical aspects.

The less obvious

In the example we’ve seen how we can decide which dependency implementation to inject, based on a configuration file, but we apparently lose this flexibility when we’re using annotations. Yes, we can use the @Qualifier annotation to determine which implementation to use, as in:

@Autowired
@Qualifier("ConsoleNotifier")
INotifier iNotifier

Yet a big chunk of the power of Spring is lost here. However, the annotation methodology leads us to two other ways to use Spring, and even in a more efficient way.
While it’s perfectly OK to select one implementation or another, it would be reasonable to decide which ones to package, say, at build time.

Let’s start with the first scenario.

  • You have a JAR containing a contract for ISerializer and ILogger you will provide to your team, or an external team, or multiple teams. They will do some implementations in different Maven projects
  • You blindly reference them in your main application using the @Autowired annotations
  • At build time, one dependency is chosen so that only the JAR I want to use is bundled

What’s present in the classpath will be used.

The second scenario is a bit trickier. Mind this is a simplification, there are more elegant ways to do it, but I want to keep the technicalities low in this article while still achieving the objective. I leave to you the search of the best way.

Assume softwares serving content to the outer world, such as a web server (or a servlet container), are delivered with Spring annotations.
In this case the control immediately looks -again- inverted. While in our previous scenario our main software is using routines delivered via Spring, in this case it’s the web server to receive a stimulation from the outer world and run a callback for that input.


See how even though My Application IS the application and has control on what happens, it is also providing some dependencies to the Servlet Container JAR that will autowire them in.
The Servlet Container is at the same time a dependency of our main application but also a consumer of dependencies we need to provide.

In this example we experience the true nature of Spring.

  • Whoever builds a compliant servlet container, is not required to expose the nature of its dialogue with the outer world, and demands the handling of the request to a dependency
  • Moreover the servlet container can rely on a logging system that will be defined by the software embedding it
  • The main application can embed any servlet container implementation that meets a contract

You can find a very minimal example in my GitHub page.

Spring.io projects

I’m definitely not going into the details of all the activities the guys at Pivotal are doing around Spring. But given what we’ve seen in the previous chapter, it seems pretty straight forward that the “pluggability” described can certainly lead to the creation of a number of modular software packages, built around Spring, allowing you to seamlessly introduce new features to your application.
You are generally used to import new dependencies using Maven or Gradle, and then using them within your application, but this goes way beyond, because when you do import a Spring module, it literally starts to interact with your code with very little effort, introducing new complex features often requiring no more than some POJOs.

Some very popular modules that I personally used are:
Spring Boot, that allows you to embed a servlet container within your application and allows you to interact with it in an astonishingly simple way. Very useful to build Java microservices.
Spring Security, a respected, rock solid system to manage access to your resources and prevent exploits
Spring Data, a rational, consistent abstraction layer to access your databases, relational or not.

And many more.

Conclusion

Maybe all this talking led me away from the main discussion: why Spring is a foundation block of Java programming, but I have a good excuse. Any foundation block is a fine balance between what it provides, and what effort is required to adopt it. The reason why I wanted to give you some hands-on examples is to demonstrate how adoption is really straight forward and tempt you to try it right away, if you haven’t already.
The “what is provides” is the toughest part, because at a glance you might be fooled to think that what it gives is not much. But this kind of patterns is something that grows in you as you use it and changes the way you think of software architecture.

To conclude, it is a foundation block because it brings order to chaos, in your code and in your mental processes.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s