1. Getting started with Spring
To start with Spring, we should have Spring JAR files. There are two ways to get Spring JAR files:
- Download the JAR files. The URL at the time of writing this tutorial is https://repo.spring.io/release/org/springframework/spring/.
- Checkout the latest code from GitHub repository and build JARs.
Spring packaging of JARs is modular. So we need not to download all the JARs. We have to use Spring modules according to the requirement. Each module has its compiled binary code in a JAR file along with corresponding JavaDoc and source JARs.
Spring has 21 modules, packaged into 21 JAR files.
The most common way to get started with Spring is using a dependency management tool such as Maven or Gradle. All we have to do it declare the dependency in a configuration file and the tool with download all the required libraries. Sometimes a module has a dependency on another module, in such situation a dependency management tool is very helpful in resolving transitive dependencies.
In this tutorial, we’ll use Maven. Maven project has a specific structure, for example src directory contains all the source code and configuration files and folders. The test directory contains the classes and configuration files that are used to test the application from the main directory.
2. Installing JDK
Spring is developed in Java. We’ll need Java installed on machine to run our program. The compatible version of Java should be installed while executing a Spring program. For example, As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE 8+) and provides out-of-the-box support for JDK 11 LTS.
Please refer to the official documentation of Spring to check the compatible Java version.
3. Hello World program without Spring
Let us first write some code to see how a basic hello world program looks like in Java without Spring.
package com.learnitweb; public class App { public static void main(String[] args) { System.out.println("Hello World!"); } }
This program is very simple. But there are few problems with this program. Let us discuss what this program is missing.
- There is no decoupling of code. A single class has everything, the message to be printed and the responsibility to print the message.
- If there is a change in message to be printed, we need to change the code (the message) of this class.
- This program prints message on the standard console. If we have to change where the message should be rendered, we can’t do that and without changing the code of this class.
- This is a very simple program, so it seems very simple to change the code to provide the message and render the message. But it could be hard to maintain in a program in a big and complex project. The responsibility to get the message and render the message should be decoupled.
3.1 What is a better solution without using Spring
Following changes can be done to our Hello World program:
- Separate the responsibility of providing the message. We can create an
interface
MessageProvider
and its implementation classHelloWorldMessageProvider
. - Separate the responsibility of rendering the message. We can create an
interface
MessageRenderer
and its implementation classConsoleMessageRenderer
. - Separate the execution of the program with rendering the message and providing the message.
Still with this solution we have create the instance of the providers and the executing class’s code will look something like the following:
public class HelloWorldExample { public static void main(String... args) { MessageRenderer messageRenderer = new ConsoleMessageRenderer(); MessageProvider messageProvider = new HelloWorldMessageProvider(); messageRenderer.setMessageProvider(messageProvider); messageRenderer.render(); } }
In this code, we still have to create the instances using new
. The responsibility of creating the dependencies lies with this class. This class is still tightly coupled with the code. Another approach could be write factory classes to which we can delegate the task of creating the instances.
So, let us see how the Hello World example would look like with Spring.
4. Hello World with Spring – XML Configuration
To get started we need to import spring-context dependency in our pom.xml:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.8</version> </dependency>
package com.learnitweb.interfaces; public interface MessageProvider { String getMessage(); }
package com.learnitweb.interfaces; public interface MessageRenderer { void render(); void setMessageProvider(MessageProvider provider); MessageProvider getMessageProvider(); }
package com.learnitweb.impl; import com.learnitweb.interfaces.MessageProvider; import com.learnitweb.interfaces.MessageRenderer; public class ConsoleMessageRenderer implements MessageRenderer { private MessageProvider messageProvider; @Override public void render() { if (messageProvider == null) { throw new RuntimeException( "No message provider. Set property for class:" + ConsoleMessageRenderer.class.getName()); } System.out.println(messageProvider.getMessage()); } @Override public void setMessageProvider(MessageProvider provider) { this.messageProvider = provider; } @Override public MessageProvider getMessageProvider() { return this.messageProvider; } }
package com.learnitweb.impl; import com.learnitweb.interfaces.MessageProvider; public class HelloWorldMessageProvider implements MessageProvider { @Override public String getMessage() { return "Hello World!"; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="provider" class="com.learnitweb.impl.HelloWorldMessageProvider" /> <bean id="renderer" class="com.learnitweb.impl.ConsoleMessageRenderer" p:messageProvider-ref="provider" /> </be
package com.learnitweb.springCore; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.learnitweb.interfaces.MessageRenderer; public class App { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml"); MessageRenderer mr = ctx.getBean("renderer", MessageRenderer.class); mr.render(); } }
Let us have a look at app-context.xml
configuration file. First the namespaces are defined. There are two beans (bean is an instance of class) with ids provider
and renderer
. p:messageProvider-ref="provider"
means the messageProvider
is referencing the provider
bean. Spring will create these dependencies for us.
5. Hello World with Spring – Using Annotation
We need not to use XML for configuration. We can also use annotations and configuration classes.
A Configuration class is a Java class annotated with @Configuration
. It contains bean definitions. Bean definitions are methods annotated with @Bean
. A configuration class can identify the beans in the application by annotating them with @ComponentScanning
.
The MessageProvider
and MessageRenderer
interfaces and their implementations will be same. The only change will be using Configuration class instead of xml. Since we are using annotation and Configuration class, we’ll use AnnotationConfigApplicationContext
in this case.
package com.learnitweb.configuration; import org.springframework.context.annotation.Bean; import com.learnitweb.impl.ConsoleMessageRenderer; import com.learnitweb.impl.HelloWorldMessageProvider; import com.learnitweb.interfaces.MessageProvider; import com.learnitweb.interfaces.MessageRenderer; public class HelloWorldConfiguration { @Bean public MessageProvider provider() { return new HelloWorldMessageProvider(); } @Bean public MessageRenderer renderer() { MessageRenderer renderer = new ConsoleMessageRenderer(); renderer.setMessageProvider(provider()); return renderer; } }
package com.learnitweb.HelloWorldAnnotation; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.learnitweb.configuration.HelloWorldConfiguration; import com.learnitweb.interfaces.MessageRenderer; public class App { public static void main( String[] args ) { ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class); MessageRenderer mr = ctx.getBean("renderer", MessageRenderer.class); mr.render(); } }