Spring approaches automated assembly from two perspectives:

  • Component scanning: Spring automatically discovers beans that need to be created in the application context.
  • Autowiring: Spring automatically satisfies dependencies between beans.

In order to explain the component scanning and automatic assembly more vividly, we take an example of a sound system, which mainly includes the following contents:

  • CD interface
  • An implementation class for the CD interface
  • CD player

The relationship between CD and CD player

A CD player isn’t much use if you don’t insert (or inject) a CD into it. So, you can say,

The CD player depends on the CD to fulfill its mission.

1. Create discoverable beans

Create CD interface CompactDisc:

package chapter02;

public interface CompactDisc {
    void play(a);
}
Copy the code

Then create an implementation class for the CD interface, SgtPeppers:

package chapter02;

import org.springframework.stereotype.Component;

@Component
public class SgtPeppers implements CompactDisc {
    @Override
    public void play(a) {
        String title = "Sgt.Pepper's Lonely Hearts Club Band";
        String artists = "The Beatles";
        System.out.println("Playing " + title + " By "+ artists); }}Copy the code

The SgtPeppers class differs from previous ones in its use of the @Component annotation.

This annotation indicates that the class will bea component class and tells Spring to create beans for the class.

So how do you get Spring to find it and create the bean?

This is where component scanning comes in, but component scanning is disabled by default in Spring.

So we need to explicitly configure Spring to find classes with @Component annotations and create beans for them.

To create the CDPlayerConfig class:

package chapter02;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class CDPlayerConfig {}Copy the code

This class differs from previous classes by using the @ComponentScan annotation, which enables Spring to enable component scanning.

By default, @ComponentScan scans the same package as the configuration class and all subpackages under that package for classes with the @Component annotation.

2. Verify component scanning

To verify that the created bean can be discovered by Spring, we create a simple JUnit test that imports the following two JAR packages:

  • Hamcrest – core – 2.1. The jar
  • Junit 4.12. The jar

You can import the JAR package as follows:

The project structure diagram after import is as follows:

package chapter02;

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 = CDPlayerConfig.class)
public class CDPlayerTest {

    @Autowired
    private CompactDisc compactDisc;

    @Test
    public void cdShouldNotBeNull(a) { assertNotNull(compactDisc); compactDisc.play(); }}Copy the code

Code simple explanation:

@ RunWith (SpringJUnit4ClassRunner. Class), at the beginning of the test automatically create a Spring application context.

@contextConfiguration (classes = cdPlayerConfig.class) tells Spring that it needs to load the configuration in CDPlayerConfig.

The @AutoWired annotation on field compactDisc will inject the SgtPeppers bean into field compactDisc because it is the implementation class of the interface compactDisc and adds the @Component annotation.

Run the test method cdShouldNotBeNull and find that the test passed and compactDisc is not null:

3. Set the bean ID

All beans in a Spring application context are given an ID, and by default Spring will lower the first letter of the class name as the bean ID.

For example, the ID of the SgtPeppers bean in the above code is SgtPeppers.

There are two ways to set the bean ID:

3.1 Setting the bean ID with @Component

@Component("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {... }Copy the code

3.2 Setting the bean ID using @named

The @named annotation is not a Spring framework annotation, but a Java Dependency Injection specification annotation, so you need to import the JAR package: Javax.inject -1.jar. For details about how to import the JAR package, see Getting Started (1) : Creating a Spring project.

import javax.inject.Named;

@Named("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {... }Copy the code

The @Component annotation is recommended in Spring projects.

4. Set the basic package for component scanning

By default, the @ComponentScan annotation scans components based on the base package in which the configuration class resides.

Sometimes, however, we put the configuration classes in a separate package to separate them from the rest of the application code.

In this scenario, the default base package will not suffice.

The @ComponentScan annotation supports passing in a specified base package in the following scenarios:

4.1 Specifying Basic Packets to Be Scanned (Single)

@ComponentScan("chapter02")
public class CDPlayerConfig {}Copy the code

Or:

@ComponentScan(basePackages = "chapter02")
public class CDPlayerConfig {}Copy the code

4.2 Specifying Basic Packets to Be Scanned (Multiple)

@ComponentScan(basePackages = {"chapter01"."chapter02"})
public class CDPlayerConfig {}Copy the code

4.3 Specifying Basic Packets to Be Scanned (Type Security)

@ComponentScan(basePackageClasses = {CDPlayer.class})
public class CDPlayerConfig {}Copy the code

The basePackageClasses also allows you to specify multiple classes in which the package will be used as the base package for the component to scan.

It is recommended to specify the base packets to scan in this type-safe manner.

5. Implement autowiring by adding annotations to beans

Autowiring is a way for Spring to automatically satisfy bean dependencies by looking for other beans in the Spring application context that match the needs of a particular bean.

To implement auto-assembly, you need to use Spring’s @AutoWired annotation.

Autowired Generally, there are three ways to use it:

5.1 Used on constructors

package chapter02;

public interface MediaPlayer {
    void play(a);
}
Copy the code
package chapter02;

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

@Component
public class CDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    @Autowired
    public CDPlayer(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

    @Override
    public void play(a) { compactDisc.play(); }}Copy the code

5.2 Use on Setter methods of properties

package chapter02;

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

@Component
public class CDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    @Autowired
    public void setCompactDisc(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

    @Override
    public void play(a) { compactDisc.play(); }}Copy the code

5.3 Used on any method of a class

package chapter02;

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

@Component
public class CDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    @Autowired
    public void insertDisc(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

    @Override
    public void play(a) { compactDisc.play(); }}Copy the code

Whether it’s constructors, Setter methods, or other methods, Spring tries to satisfy the dependencies declared on method parameters.

If there is one and only one bean that matches the dependency requirement, that bean will be assembled.

If there is no matching bean, Spring throws an exception when the application context is created.

This exception can be avoided by setting the require attribute to false:

@Autowired(required = false)
public CDPlayer(CompactDisc compactDisc) {
    this.compactDisc = compactDisc;
}
Copy the code

However, caution is recommended to avoid not finding beans to match and nullPointerExceptions appearing in code without null checking.

If more than one bean satisfies the dependency, Spring will throw an exception indicating that it is not explicitly specified which bean to select for autowiring.

The @AutoWired annotation can also be replaced with the @Inject annotation (derived from the Java dependency injection specification), which also implements auto-assembly:

package chapter02;

import org.springframework.stereotype.Component;
import javax.inject.Inject;

@Component
public class CDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    @Inject
    public CDPlayer(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

    @Override
    public void play(a) { compactDisc.play(); }}Copy the code

The @Autowired annotation is recommended in Spring projects.

6. Verify automatic assembly

Modify CDPlayerTest class code to test auto – assembly.

package chapter02;

import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
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;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {

    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();

    @Autowired
    private MediaPlayer mediaPlayer;

    @Autowired
    private CompactDisc compactDisc;

    @Test
    public void cdShouldNotBeNull(a) {
        assertNotNull(compactDisc);
        compactDisc.play();
    }

    @Test
    public void play(a) {
        mediaPlayer.play();
        assertEquals("Playing Sgt.Pepper's Lonely Hearts Club Band By The Beatles\r\n", log.getLog()); }}Copy the code

The StandardOutputStreamLog class is used in this code, so you need to import the jar package: system-rules-1.16.0.jar.

MediaPlayer = CDPlayer bean = CDPlayer bean = CDPlayer bean

7. Source code and reference

Source code address: github.com/zwwhnly/spr… Welcome to download.

Craig Walls: Spring In Action (4th Edition)