Spring Core | Beans & Wiring | Part- 2

In our previous post, we learned how we can create beans automatically by using @Component and wire them with other object’s using @Autowired . Just to give a quick summary, there are different ways to create beans and wire them within a Spring container :

  • Automatic bean discovery and wiring (We discussed this in our last post)
  • Explicit configurations in XMLs
  • Explicit configurations in Java

In this post, we will be focusing on how we can create beans using Java configurations.

While building a Java application, you often use some third-party libraries to perform some functions. In a project, you may require to create a bean of a class that belongs to the library. So naturally, you won’t be able to annotate the class with Component  or Autowired  because you don’t have the source code for that library. This is the time when the automatic configuration isn’t an option and you must turn to explicit configurations.

2. Explicit Configurations in Java

So we will be learning how to do these explicit configurations in Java now. I prefer JavaConfig because it’s more powerful, type-safe, readable and refactor-friendly. It’s just like any other Java code in your application.

Even though these explicit configurations are Java code, we must understand that it is configuration code and set it apart from our business logic in an application. We should not add configuration in between our business logic and vice-versa. It’s often a best practice to keep JavaConfig in a separate package.

Now, let us see how we can configure Spring using JavaConfig.

2.1 Creating a configuration class

In our previous post, we created a configuration StudentConfig  where we rely on component scanning using @ComponentScan so that Spring creates a bean of a class annotated with @Component. Let us revisit StudentConfig . We will be removing @ComponentScan  annotation from the config class in this case.

package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration
public class StudentConfig{
}

If you see the above code snippet, we annotated the class using just @Configuration . This annotation identifies it as a configuration class, where we will be configuring the details of the beans, that are needed to be created in Spring container.

2.2 Declaring Beans

Now In order to create a bean, we need to write a method that will be annotated with @Bean and return the object of the desired class. It will instruct Spring that any object returned by this method should be registered as a bean in Spring container. Let us understand it with the help of an example.

In our previous post, we looked at an interface Subject  and class History . We will remove @Component from the class History to illustrate how we can create its bean explicitly.

package com.lifeinhurry.person;
public Interface Subject{
    public void attend();
}
package com.lifeinurry.person;
public class History implements Subject{
     private String content = "history chapter";
     @Override
     public void attend(){
         System.out.print("Reading :" + content);
     }
}

So now History  is a plain vanilla class which implements Subject interface and override its function. Let us see how we can create a bean of this class in a Spring container.

package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration 
public class StudentConfig{
    @Bean
    public Subject history(){
        return new History();
    }
}

In the above code snippet, @Bean  annotation indicates that the method will return an instance of a type Subject and Spring will register it as a bean in its container/application context. By default, the bean will be represented by the method’s name. However, we can also rename the bean using name attribute below:

package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration 
public class StudentConfig{
    @Bean(name="customName")
    public Subject history(){
        return new History();
    }
}

2.3 Wiring with JavaConfig

We created a bean of the type Subject above. Now we will learn how we can wire this bean into a class Student that depends on it using JavaConfig. The simplest way to do that is to simply call the referenced bean’s method:

package com.lifeinhurry.person;
public class Student implements Person{
    private Subject subject;
    public Student (Subject subject) {
         this.subject= subject;
    }
    public void attendSubject() {
         subject.attend();
    }
}
package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration 
public class StudentConfig{
    @Bean
    public Subject history(){
        return new History();
    }
    @Bean
    public Student student(){
        return new Student(history());
    }
}

If you notice, student() is annotated with @Bean which means it will also be registered as a bean in Spring container and its ID will be student , the same as the method’s name. In the above example, when we call history() inside student() , Spring will ensure that it finds the bean in its container and wire it to an instance of the class Student .

There are other methods to wire components together as well. Let us see that.

package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration 
public class StudentConfig{
    @Bean
    public Subject history(){
        return new History();
    }
    @Bean
    public Student student(Subject subject){
        return new Student(subject);
    }
}

In the above example, student() method just takes subject as a parameter. When method student() is invoked by Spring to create its bean, it autowires the subject based on the type and satisfies its dependency. Let us verify it using the JUnit test.

package com.lifeinhurry;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=StudentConfig.class)
public class StudentTest{ 
    @Autowired
    private Subject subject;
    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();
    @Autowired
    private Student student;
    @Test
    public void subjectShouldNotBeNull()
    {
        assertNotNull(subject);
    }
    @Test
    public void testAttendSubject()
    {
        assertEquals(
            "Reading :history chapter",
            log.getlog());
    } 
}

The above test passes with flying colors.

2.4 Importing and Mixing Configurations

I hope by now you are clear with the concept of different ways to define beans in a spring container and how to wire them. We discussed 2 types of configurations until now.  In an enterprise-level Java application, there are many components that are working in coordination to satisfy a common goal. There are a lot of aspects involved while designing such an application and you may require to use both automatic and explicit configuration depending upon the need. Fortunately, none of the configuration options available in Spring are mutually exclusive. You’re free to mix component scanning and autowiring with JavaConfig and/or XML configuration. In Spring it doesn’t matter how the beans are being wired together until and unless it exists in a spring container. Let us understand this with the help of an example.

Above we saw both Student as well as Subject are defined in a single configuration class. What if we want both entities config to be separate.

package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
@Configuration 
public class SubjectConfig{
    @Bean
    public Subject history(){
        return new History();
    }
}
package com.lifeinhurry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration 
@Import(SubjectConfig.class)
public class StudentConfig{
    @Bean
    public Student student(Subject subject){
        return new Student(subject);
    }
}

In the above code snippet, we see that we separated the two configs. But we need a way to bring these two configuration classes together. We imported SubjectConfig into StudentConfig using @Import annotation.

Conclusion

So by now, we learned that Spring container/application-context is the core of a Spring Framework. Spring manages the lifecycle of a bean in a container, creating beans and wiring them together so they can do their job in an application. We also learned different ways to configure and wire beans together. We will be learning some advanced wiring techniques next as part of this series where we will see how to wire beans based on conditions, how to resolve ambiguity in case there are multiple beans of the same type in a container, etc. I will highly recommend you to keep following the series for more topics on Spring Framework.

I hope I am able to clear the basic concepts of spring core by now. In case of any queries or doubts please feel free to drop a comment and I will get back to you as soon as possible.