In this article, we are going to look at the core spring dependency example, this article would be lengthy as I tried to cover different types of dependency injection available in Spring Core and added a bit of console based input driven functionality to demonstrate how we can change injected dependency at runtime based on user’s input.

To change injected dependency at runtime, I have used interfaces to load and assign beans. So if you are not sure about interfaces, I would suggest that you go through this nice article on interfaces at oracle docs before continuing this article.

If you are at this point, I am assuming you are fully ready to understand Spring’s dependency injection. So let’s start.

 

Maven as Build Tool

We are going to use Maven as build tool to build our project, and we will package our project as jar. First step we will take is to create this type of directory structure at your given directory. So open up your terminal and hit below commands,

 

cd <DIRECTORY_OF_YOUR_CHOICE>
mkdir SpringCoreDependencyExample
cd SpringCoreDependencyExample
mkdir -p src/main/java/org/milansavaliyaz/springsimpleapplication

Once we are ready with above directory structure, next thing we will do is to create pom.xmlfile in our project’s root directory to help maven identify what we want for our project and on which other projects our project depends on.

So, again in terminal hit this command to create blank, pom.xml file,

touch pom.xml

Now, open pom.xml file and paste below code into it, I’ll exmpalin in a bit what each part of code is doing. 🙂

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.milansavaliyaz</groupId>
    <artifactId>SpringSimpleApplication</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>

    </dependencies>
</project>

 

Each Maven version supports specific model version, and currently, in Maven 3 it’s, 4.0.0. So you will always set it to 4.0.0 if you are using Maven 3 as there is no other model available currently.

Then second, tag in the pom indicates groupId, which basically like, root member of the family. Maven used this tag to organise all the child project ( identified by artifactId tag under groupId)

Version is very simple enough as it indicates current version of your project. Then the packaging tag says maven to package whole project as jar. You can give its value as war if you are building Web based application.

Then there is property tag which Maven uses to build our project in accordance with Java’s which version. In our case, we are using Java8.

Then there is dependencies tag in which, we declares all the dependencies of our project, maven will take care of organising those all for us when it builds the project.

So that’s all, there is to understand pom.xml file. Currently, we are only relying on spring-context dependency.

Next section would be of real code which you can write in your favorite IDE. I am using IntellijIdea, so screenshots would be of that IDE.

Final project directory Structure would look like this in the screenshot.

 

 

What are we developing ?

We will develop a console based application which will take input from the user and format that input according to the user choice. We will offer input conversion to either LOWERCASE or UPPERCASE.

We will start our design with simple interface called StringFormatter which will server as skeleton for our input convertors.

Here is the code of StringFormatter interface.

package org.milansavaliyaz.springsimpleapplication.stringformatters;

/**
 *
 * @author Milan Z. Savaliya
 */
public interface StringFormatter {
  String formatString(String strToFormat);
}

As you can see, this interface promises us to have one method which we can call to convert any string to specific format. We will create formatters in a bit.

Our next, job is to create two formatters implementing StringFormatter interface. So let’s codeLowercaseStringFormatter first,

package org.milansavaliyaz.springsimpleapplication.stringformatters;

/**
 *
 * @author Milan Z. Savaliya
 */
public class LowercaseStringFormatter implements StringFormatter{

  @Override
  public String formatString(String strToFormat) {
    return strToFormat.toLowerCase();
  }
  
}

And then, UppercaseStringFormatter,

package org.milansavaliyaz.springsimpleapplication.stringformatters;

/**
 *
 * @author Milan Z. Savaliya
 */
public class UppercaseStringFormatter implements StringFormatter{

  @Override
  public String formatString(String strToFormat) {
    return strToFormat.toUpperCase();
  }
  
}

Once, we have two Formatters. We will create StringPrinter component[ I’ll explain in a bit about what is component ] which will have StringFormatter field and its setter method along with method which executes formatString method on StringFormatter instance.

package org.milansavaliyaz.springsimpleapplication;

import org.milansavaliyaz.springsimpleapplication.stringformatters.StringFormatter;
import java.io.File;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *
 * @author Milan Z. Savaliya
 */

@Component
public class StringPrinter{
  private StringFormatter stringFormatter;

  @Autowired
  public void setStringFormatter(StringFormatter stringFormatter) {
    this.stringFormatter = stringFormatter;
  }
  
  
  public void printMessage(String messageToPrint){
    System.out.println(this.stringFormatter.formatString(messageToPrint));
  }
  
}

Now as we have code in its place, let’s understand what is a component. 🙂

Component is simple POJO class, a bean more specifically which we can auto wire in other places. Normally when you have control over source code, you’ll annotate that class with @Component annotation and spring will take care of its instantiation on your behalf.

Simple enough right? Our next job is to create StandardInputStringHandler component which will simply be the interface in between client code and console based inputs of users.

We will code this one using interface too as if in any case we want to provide a different implementation for input handling, we can do that with ease. Currently, we are only focusing on console based input but what if in future we want to use file based input or something else? We can easily switch our implementation if we have coded to an interface than implementation. And that’s what we will do in this case too.

So this would be our interface for all the input handlers.

package org.milansavaliyaz.springsimpleapplication.inputhandlers;

/**
 *
 * @author Milan Z. Savaliya
 */
interface StringInputHandler {
  int getInputCode();
  boolean userWantsToContinue();
  String getCurrentInput();
}

This interface is quite simple, all we are promising is to having an method which will return inputCode as integer value, a method will will indicate if user wants to continue and method will we return user input string.

Then we will create our first simple standard console based input handler.

package org.milansavaliyaz.springsimpleapplication.inputhandlers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Scanner;

/**
 * @author Milan Z. Savaliya
 */
@Component
public class StandardInputStringInputHandler implements StringInputHandler {
    private String currentInput = "";
    Scanner scanner;

    @Autowired
    public void setScanner(Scanner scanner) {
        this.scanner = scanner;
    }


    @Override
    public int getInputCode() {
        System.out.println("Enter line to convert case ");
        this.currentInput = this.scanner.next();
        System.out.println("1> To Lowercase");
        System.out.println("2> To Uppercase");
        return this.scanner.nextInt();
    }

    @Override
    public boolean userWantsToContinue() {
        System.out.println("Want to continue? [yY/nN]");
        String input = this.scanner.next();
        return input.equalsIgnoreCase("y");
    }

    public String getCurrentInput() {
        return currentInput;
    }


}

Here, we are Auto wiring instance of Scannerclass. We will create a bean of that class soon from our Main Application starter class. Notice here that we are not annotating with @Component but with @Bean because we are not having total control over the source code of the Scanner class. We are relying on Java’s implementation of Scanner class.

Now, this is our main starter class which will start the spring boot process.

package org.milansavaliyaz.springsimpleapplication;

import org.milansavaliyaz.springsimpleapplication.inputhandlers.StandardInputStringInputHandler;
import org.milansavaliyaz.springsimpleapplication.stringformatters.LowercaseStringFormatter;
import org.milansavaliyaz.springsimpleapplication.stringformatters.StringFormatter;
import org.milansavaliyaz.springsimpleapplication.stringformatters.UppercaseStringFormatter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

import java.util.Scanner;

/**
 * @author Milan Z. Savaliya
 */
@Configuration
@ComponentScan
public class MainStarter {

    @Bean
    @Qualifier("scanner")
    Scanner getScanner() {
        return new Scanner(System.in);
    }

    @Bean
    @Qualifier("uppercaseFormatter")
    StringFormatter uppercaseFormatter() {
        return new UppercaseStringFormatter();
    }

    @Bean
    @Qualifier("lowercaseFormatter")
    @Primary
    StringFormatter lowercaseFormatter() {
        return new LowercaseStringFormatter();
    }

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainStarter.class);

        StringPrinter stringPrinter = context.getBean(StringPrinter.class);
        StringFormatter uppercaseFormatter = context.getBean(UppercaseStringFormatter.class);
        StringFormatter lowercaseFormatter = context.getBean(LowercaseStringFormatter.class);

        StandardInputStringInputHandler inputHandler = context.getBean(StandardInputStringInputHandler.class);

        int input = 1;
        while (input == 1 || input == 2) {
            input = inputHandler.getInputCode();
            if (input == 1) {
                stringPrinter.setStringFormatter(lowercaseFormatter);
                stringPrinter.printMessage(inputHandler.getCurrentInput());
            } else if (input == 2) {
                stringPrinter.setStringFormatter(uppercaseFormatter);
                stringPrinter.printMessage(inputHandler.getCurrentInput());
            }
            if (!inputHandler.userWantsToContinue()) {
                break;
            }
        }

    }
}

This class deserves a lot of explaining as this is where are doing a lot of work regarding dependency injection. So let’s start the explanation of each bit of this class.


    @Bean
    @Qualifier("scanner")
    Scanner getScanner() {
        return new Scanner(System.in);
    }

We have created a method which returns the instance of Scanner class bound to the standard input stream System.in. We have annotated this method with @Bean annotation which tells spring to inject this bean into Container so when we need it we can either autowire it or get it from the container itself by using its name “scanner”. @Qualifier annotation tells spring that this bean should be mapped with the provided name.



    @Bean
    @Qualifier("uppercaseFormatter")
    StringFormatter uppercaseFormatter() {
        return new UppercaseStringFormatter();
    }

    @Bean
    @Qualifier("lowercaseFormatter")
    @Primary
    StringFormatter lowercaseFormatter() {
        return new LowercaseStringFormatter();
    }

First method is simple enough as its exactly same as the Scanner bean method. But interesting part here is the annotation `@Primary` which tells spring that if there are two instances reference into the same type, use this one as primary and when we need another one, we will use its name specified to spring by @Qualifier annotation.

Remeber, we are using StringFormatter interface to hold all the implementation as we want to switch back and forth whenever we need to use another string formatter implementation. So basically we are storing two instances [ UppercaseStringFormatter and LowercaseStringFormatter ] into the same reference type [ StringFormatter ]. So we are indicating that our primary choice of interest is LowercaseStringFormatter.


        ApplicationContext context = new AnnotationConfigApplicationContext(MainStarter.class);

        StringPrinter stringPrinter = context.getBean(StringPrinter.class);
        StringFormatter uppercaseFormatter = context.getBean(UppercaseStringFormatter.class);
        StringFormatter lowercaseFormatter = context.getBean(LowercaseStringFormatter.class);

        StandardInputStringInputHandler inputHandler = context.getBean(StandardInputStringInputHandler.class);

This is the code of main method which needs explantaion. First we are craeting an instance of AnnotationConfigApplicationContext and storing it into the ApplicationContext which is interface which AnnotationConfigApplicationContext implements. We are supplying our MainStarter.class to tell spring that this is our starting point and it can use it to further investigate and instantiate Spring Container.

Then in the next 4 lines, we are asking Spring to return the bean of provided class. We are storing our StringFormatters into the reference of StringFormatter interface so that we can change it based on user’s choice. Rest code is self-explanatory. 🙂

​Download Source Code