Spring 5 Fundamentals: Spring Configuration Using Java

At last, we’ll be using Spring! This post is part of my Spring 5 Fundamentals series, where I will be going through this Pluralsight course, Spring Framework: Spring 5 Fundamentals by Bryan Hansen. If you haven’t read my intro post to this series, click here. My previous article is about setting up Spring, which is kinda a prerequisite for this post here. 😉

If you’ve gotten Spring and our sample app set up, let’s continue onwards and learn how to configure Spring using Java.

Java Configuration Introduction

The key point of Java configuration is there’s no XML. Normally in Spring, an applicationContext.xml file contains all of your configuration. However with Java configuration, this file does not exist. We will have a context file, but it will not be configured in XML.

Demo

Copy Project

Let’s make a duplicate of our previous conference project. All you need to do is go to the location of the conference folder in your directory and copy-paste it. I named my new folder “conference-java”.

Okay, this probably didn’t even need a screenshot.

Open up the new project. There’s only one change you’ll need to make. We’ll need to change the artifactId to “conference-java” in the POM file of this new project to avoid any potential conflicts.

<artifactId>conference-java</artifactId>

To make sure everything is working fine, try running the Application code again. It should return the same result as previously.

App Config

Our first step in app configuration is creating a file where we can Bootstrap everything at.

  1. Navigate to our src > main > java folder in our project.
  2. Right-click on it and create a new Java class.
  3. Let’s call it “AppConfig”.

Now we have a file to start Bootstrapping our application, which will be the start of our application context. All of our configuration starts at this point. We’ll need to add our annotations to this, but first, let’s go over what annotations are.

@Configuration

We can use @ to indicate an annotation. Java files that contain the @Configuration annotation replace the XML files that were used in the past. So essentially, the applicationContext.xml files are replaced by @Configuration, and files with this line indicates that it is to be used for configuration purposes.

@Configuration is a class-level annotation. Methods used in conjunction with the @Bean annotation are used to get instances of Spring beans. In other words, these methods return an instance of a bean, and the bean is now registered inside of Spring and is available for us to use inside our Spring application.

So let’s actually add configuration to our AppConfig file.

import org.therenaissance.service.SpeakerService;
import org.therenaissance.service.SpeakerServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
	@Bean (name = "speakerService")
	public SpeakerService getSpeakerService() {
		return new SpeakerServiceImpl();
	}
}

Note that giving the bean a name is optional.

And that’s it! We’ve Spring-enabled our application, told it to configure it as a Spring app, and we created a bean called “speakerService”.

Setter Injection

A setter injection using the Java approach is as simple as a method call. It is just calling a setter on a bean, which we can define using the bean annotation as seen previously. We are not going to call an instance we create; rather, we are calling an instance of the bean from the Spring configuration file.

By the way, beans are singletons by default and will only execute the method the first time they are called.

SpeakerServiceImpl file

To implement a setter injection, we will need to remove some of the code we have hardcoded before. Let’s change a few things in SpeakerServiceImpl.

First off, change the SpeakerRepository declaration to the following:

private SpeakerRepository repository;

Next, we’ll create a setter for this SpeakerRepository object. Remember how to do that? Right-click > Generate > Setter. Now we have converted our SpeakerServiceImpl to be injected rather than hardcoded. This is what our SpeakerServiceImpl class looks like now.

package org.therenaissance.service;

import org.therenaissance.model.Speaker;
import org.therenaissance.repository.SpeakerRepository;
import java.util.List;

public class SpeakerServiceImpl implements SpeakerService {
	private SpeakerRepository repository;

	@Override
	public List<Speaker> findAll() {
		return repository.findAll();
	}

	public void setRepository(SpeakerRepository repository) {
		this.repository = repository;
	}
}
AppConfig file

Now let’s head over to AppConfig and make some changes there too. First off, let’s add a new bean.

@Bean (name = "speakerRepository")
public SpeakerRepository getSpeakerRepository() {
	return new HibernateSpeakerRepositoryImpl();
}

Then we’ll need to edit our getSpeakerService() method to this.

@Bean (name = "speakerService")
public SpeakerService getSpeakerService() {
	SpeakerServiceImpl service = new SpeakerServiceImpl();
	service.setRepository(getSpeakerRepository());
	return service;
}

If you recall, in this method, we previously returned a SpeakerServiceImpl object using the keyword new. However, now we’re assigning it to a variable and using setRepository to interact with the service, thus we are using setter injection to inject our repository into SpeakerServerImpl.

We do it this way to ensure that the SpeakerRepository instance is a singleton as it is a bean rather than just a normal object.

Application file

Now that we’ve got this configured to use beans, it’s all wired up. Let’s move on to our Application file to configure it to use Spring. Add the following to your Application.java class.

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.therenaissance.service.SpeakerService;

public class Application {
	public static void main(String args[]) {
		ApplicationContext appContext = new AnnotationConfigApplicationContext(AppConfig.class);
		SpeakerService service = appContext.getBean("speakerService", SpeakerService.class);
		System.out.println(service.findAll().get(0).getFirstName());
	}
}

The object we’re passing into AnnotationConfigApplicationContext() is our own AppConfig class. Recall that in its java file, we used @Configuration to declare it as a configuration file; thus, we are able to use it here.

By adding these lines, we are loading Spring and our configuration file into our Application Context.

Let’s glance back at our AppConfig class.

@Configuration
public class AppConfig {
	@Bean (name = "speakerService")
	public SpeakerService getSpeakerService() {
		SpeakerServiceImpl service = new SpeakerServiceImpl();
		service.setRepository(getSpeakerRepository());
		return service;
	}

	@Bean (name = "speakerRepository")
	public SpeakerRepository getSpeakerRepository() {
		return new HibernateSpeakerRepositoryImpl();
	}
}

What happens when this code runs is it’s going to create a basic registry with two beans in it – speakerService and speakerRepository. In getSpeakerService(), we are injecting the speakerRepository bean into the speakerService bean. And then we’ll return that back into our application when we call it.

Now that we know what’s happening, let’s look at this line back in our Application class.

SpeakerService service = appContext.getBean("speakerService", SpeakerService.class);

We are passing the speakerService bean by its name as well as its class. This is the final step before we can run our program. Let’s do that now and see what pops up in the console!

Dog

Process finished with exit code 0

Ayyyoo we got the same instance as before, which means our program works! Now nothing inside our application is hardcoded as it’s all done by our configuration instances. In other words, all of those lines using the new keyword only exist in our AppConfig file.

Constructor Injection

Now let’s see what this would look like using constructor injection. In your SpeakerServiceImpl file, add this constructor method to your class.

public SpeakerServiceImpl(SpeakerRepository repository) {
	this.repository = repository;
}

And to your AppConfig file, we will have to edit getSpeakerService() to look like this.

@Bean (name = "speakerService")
public SpeakerService getSpeakerService() {
	SpeakerServiceImpl service = new SpeakerServiceImpl(getSpeakerRepository());
	return service;
}

All we’re really doing is setting our repository as we construct it rather than creating an uninitiated SpeakerServiceImpl object and then setting a repository for it.

Running the code will return the same result, so we know it works. Whichever injection style you want to use is up to you!

Conclusion

And there we go, we’ve officially ran a Spring application! In my next post, we will go over Spring Scopes and Autowiring.

Leave a Reply

Your email address will not be published. Required fields are marked *