Spring loosely coupled example

The concept of object-oriented is a good design to break your system into a group of reusable objects. However, when system grows larger, especially in Java project, the huge object dependencies will always tightly coupled causing objects very hard to manage or modify. In this scenario, you can use Spring framework to act as a central module to manage all the object dependencies easily and efficiently.

Output Generator Example

Let’s see an example, assume your project has a function to output the content to Csv or Json format. Your code may look like the following example:

File : IOutputGenerator.java – An interface for output generator


package com.mkyong.output;

public interface IOutputGenerator
{
	public void generateOutput();
}

File : CsvOutputGenerator.java – A Csv output generator to implement the IOutputGenerator interface.


package com.mkyong.output.impl;

import com.mkyong.output.IOutputGenerator;

public class CsvOutputGenerator implements IOutputGenerator
{
	public void generateOutput(){
		System.out.println("Csv Output Generator");
	}
}

File : JsonOutputGenerator.java – A Json output generator to implement the IOutputGenerator interface.


package com.mkyong.output.impl;

import com.mkyong.output.IOutputGenerator;

public class JsonOutputGenerator implements IOutputGenerator
{
	public void generateOutput(){
		System.out.println("Json Output Generator");
	}
}

There are couple of ways to call the IOutputGenerator, and how to use Spring to avoid objects to coupled tightly with each other.

1. Method 1 – Call it directly

Normal way, call it directly.


package com.mkyong.common;

import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;

public class App 
{
    public static void main( String[] args )
    {
    	IOutputGenerator output = new CsvOutputGenerator();
    	output.generateOutput();
    }
}

Problem
In this way, the problem is the “output” is coupled tightly to CsvOutputGenerator, every change of output generator may involve code change. If this code is scattered all over of your project, every change of the output generator will make you suffer seriously.

Method 2 – Call it with helper class

You may think of creating a helper class to move all the output implementation inside.


package com.mkyong.output;

import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;

public class OutputHelper
{
	IOutputGenerator outputGenerator;
	
	public OutputHelper(){
		outputGenerator = new CsvOutputGenerator();
	}
	
	public void generateOutput(){
		outputGenerator.generateOutput();
	}
	
}

Call it via helper class.


package com.mkyong.common;

import com.mkyong.output.OutputHelper;

public class App 
{
    public static void main( String[] args )
    {
    	OutputHelper output = new OutputHelper();
    	output.generateOutput(); 
    }
}

Problem
This looks more elegant, and you only need to manage a single helper class, however the helper class is still tightly coupled to CsvOutputGenerator, every change of output generator still involves minor code change.

Method 3 – Spring

In this scenario, Spring Dependency Injection (DI) is a good choice. Spring can make your output generator loosely coupled to the output generator.

Minor change in OutputHelper class.


package com.mkyong.output;

import com.mkyong.output.IOutputGenerator;

public class OutputHelper
{
	IOutputGenerator outputGenerator;
	
	public void generateOutput(){
		outputGenerator.generateOutput();
	}
	
	public void setOutputGenerator(IOutputGenerator outputGenerator){
		this.outputGenerator = outputGenerator;
	}
}

Create a Spring bean configuration file and declare all your Java object dependencies here.


<!-- Spring-Common.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<bean id="OutputHelper" class="com.mkyong.output.OutputHelper">
		<property name="outputGenerator" ref="CsvOutputGenerator" />
	</bean>
	
	<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" />
	<bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" />
		
</beans>

Call it via Spring


package com.mkyong.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mkyong.output.OutputHelper;

public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext context = 
    	   new ClassPathXmlApplicationContext(new String[] {"Spring-Common.xml"});

    	OutputHelper output = (OutputHelper)context.getBean("OutputHelper");
    	output.generateOutput();
    	  
    }
}

Now, you just need to change the Spring XML file for a different output generator. When output changed, you need to modify the Spring XML file only, no code changed, means less error.

Conclusion

With Spring framework – Dependency Injection (DI) is a useful feature for object dependencies management, it is just elegant, highly flexible and facilitates maintainability, especially in large Java project.

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
Somapala
Guest
Somapala

With JavaConfig no XML based bean configuration is required, so everytime you have to change annotations in the java classes when you need to change the output method, so how we can achieve this loose coupling with annotations? Is this specific to xml based bean injection?

Parag
Guest
Parag

Good concept of loose coupling and DI

La VloZ
Guest
La VloZ

Why creating helper class wrapper? why not using factory method pattern instead?

Arun Singh
Guest
Arun Singh

very nice sir. Thanks. Other tutorials on internet are not capable to explain this concept properly. Thanks

Deepthi Vikram
Guest
Deepthi Vikram

Very good explaination of DI, the example is very clear. Thanks!!

Prem Pratick Kumar
Guest
Prem Pratick Kumar

Example could have been better.

Anuj Dubey
Guest
Anuj Dubey

Amazing Example Helps Alot…….Thanks

Karimoune
Guest
Karimoune

Excelent !

Ranveer
Guest
Ranveer

bad example

Singh
Guest
Singh

why?

Raghvendra kumar
Guest
Raghvendra kumar

good example

jack willam
Guest
jack willam

pefect

wholet
Guest
wholet

gereat

jeff
Guest
jeff

Great Example! Thanks Mr.Mkyong for clear explanation and showing the differences between three approaches. Great work! Keep it up.

Bogdan
Guest
Bogdan

Or simplier, without Helper and no coupling :

ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {“SpringBeans.xml”});

IOutputGenerator output = (IOutputGenerator)context.getBean(“JsonOutputGenerator”);
output.generateOutput();

BelianskyAS
Guest
BelianskyAS

And you have to change source code, when you need to use the CsvOutputGenerator. This is tight coupling.

p.s. Sorry my bad english :)

Steve J
Guest
Steve J

I am not sure why people say changing the spring config is not a code change. The bad part about changing the spring config file is that it is not under unit test so there is no easy to tell if you have broken anything…

Alex
Guest
Alex

Assuming you define (needs to be the same, because product owner said so) and call the output.generateOutput in more than one class, if you need to change to Csv you will have to modify 2 or more classes, instead of 1 xml file. Low Coupling is also defined by extensibility, not only by what your source code looks like at the moment.

Umer
Guest
Umer

Steve,

I have used my actual spring configuration file under my unit test case, all of my test code use actual spring configuration file, so If we have make incorrect changes in spring configuration , my test case start getting failed, but I also agree spring configration change is a ” CHANGE “.

ramandeep89
Guest
ramandeep89

Hey Steve, spring config is actually not a code change. Consider the scenario below:
You have an application deployed on your server, and you need to change the implementation. If you have to change it in a java class, you need to compile the class first, build it and redeploy it. For spring config, change xml on the fly and you are set, no compilation, no build :)
PS: I assume you have the other implemetation ready on the server already.

Abhilash
Guest
Abhilash

Still you have to restart the application for it to pickup latest changes right ? Wont that be a serious flaw ? Why cant we get a particular bean dynamically based on some parameter ?
Let me know if I have understood it wrong.

mohiadeen
Guest
mohiadeen

Nice explanation . thanks :)

manisg
Guest
manisg

hjkhjk

Ayaz
Guest
Ayaz

Its good tutorial but my question is it looks same just the difference is you placed bean.xml what if i want that both can be accessed by xml like csv and xml both. sory if my question is wrong because iam new in spring. but regular reader of your articles. Thanks

Abdul Gafoor
Guest
Abdul Gafoor

Excelent clarification…

Selvakumar
Guest
Selvakumar

cool Example

Rajpal Singh
Guest
Rajpal Singh

Hello sir,

You said that when output changed, you need to modify the Spring XML file only.

Can you explain with example what type of code we change in the output.

Help me…..

Chandra Sekhar
Guest
Chandra Sekhar

As per the below configuration,

we are attaching a CsvOutputGenerator to the OutputHelper. If we want to attach JsonOutputGenerator, then we change the spring configuration as below:

Hope this clarifies ?

Victor
Guest
Victor

And what should we do if we want to attach booth CsvOutputHelpere and JsonOutputHelper ?

Suri
Guest
Suri

I don’t get it. Instead of one helper class for each implementation, we are ending up with one spring config for each implementation. Is the advantage here the ability to execute implementation of choosing without re-compiling ?

Suri
Guest
Suri

Sorry ! spoke too soon. Very first comment and subsequent reply by Mr.Yong, made me believe I should be thinking differently. I am very glad I found this site Mr.Yong, Thank you.

Srikanth
Guest
Srikanth

Really useful….keep posting like these…

Rajesh Kumar
Guest
Rajesh Kumar

Nice, precise and clear information. Thanks.

Trivi
Guest
Trivi

Hi mkyong,

Great help to the java community, best regards.

Suyog
Guest
Suyog

can anyone tell me what is the difference between ApplicationContext and BeanFactory

 ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"context.xml"}); 
 BeanFactory context = new ClassPathXmlApplicationContext(context.xml); 
ironhide
Guest
ironhide

ApplicationContext container includes all functionality of the BeanFactory container, so it is generally recommended over the BeanFactory.

BeanFactory can still be used for light weight applications like mobile devices or applet based applications where data volume and speed is significant

Suyog
Guest
Suyog

// this is for CsvOutputGenerator but what to do if i want both CsvOutputGenerator and sonOutputGenerator
//can i write like this

TestConfig
Guest
TestConfig

call like this

OutputHelper output = (OutputHelper)context.getBean(“OutputHelper”);
output.generateOutput();

OutputHelper output1 = (OutputHelper)context.getBean(“OutputHelper1”);
output1.generateOutput();

pizero
Guest
pizero

:)))
output, output1, outputhelper, outputhelper1 ….. :)))

so all of you think that naming variables like a1, a2, a3 and so on
is elegant and readable?

very interesting ….

Muhammad Amjad
Guest
Muhammad Amjad

Excellent Document, Or i can say excellent website, Each step is explained in detail and we can easily understand the stuff

Welldone Mr. Mkyong

Shawn C
Guest
Shawn C

totally agree ! excellent work !

sreenivas
Guest
sreenivas

neat and clean explaination…. thanks a lot boss !!!!!!!!!

sreenivas
Guest
sreenivas

Very good explaination….. Thanks alot…

Azhar
Guest
Azhar

Cool example,