IOC and DI have been introduced above. IOC is a design pattern, and DI is its concrete implementation. There are many frameworks with such implementation.

How does Spring add objects to containers

Spring adds objects to containers in a variety of ways, most notably XML and annotations, which are more widely used today, so we’ll focus on the annotation injection model here.

There are many kinds of annotations under Spring, and the most widely used one is schema annotations.

Stereotype Annotations

@Component @service @controller @repository @Configuration @component @service @controller @repository @configuration

If a class is annotated with @Component, it will be scanned and added to the container. Here we use the spring way to implement the previous article to obtain the hero requirements.

Put a @Component annotation for Diana, the hero:

@Component public class Diana{ private String skillName = "Diana R"; public Diana() { } public void q(){ System.out.println("Diana Q"); } public void w(){ System.out.println("Diana W"); } public void e(){ System.out.println("Diana E"); } public void r(){ System.out.println(this.skillName); }}Copy the code

Let’s say I have a Controller that needs Diana

@RestController public class BannerController { @Autowired private Diana diana; @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET}) public String test() { diana.r(); return "Hello SpringBoot"; }}Copy the code

Autowired means that we inject an object here, and then we launch the application,

Through the browser to http://localhost:8081/v2/banner, you’ll find in the console output of Diana r method to print content, here really got the Diana this object.

Object injection timing

See what happens if we remove the @Component annotation from Diana, leave everything else unchanged, and run the program.

We are prompted with the following error when we restart:

The application did not find the corresponding bean, which means that I need to inject the bean, but I did not find it in the container.

This leads to the conclusion that the container will inject objects into the corresponding snippet of code after initialization.

Autowired(Required =true) is set to true by default, indicating that the object must exist at the time of injection or the injection will fail. Autowired(Required =false) does not return an error, but does return a null pointer exception.

So when does the spring container instantiate the object, when the controller is accessed, or when the container is started? We can check this by putting a print statement in Diana’s no-argument constructor and then starting the program:

public Diana() {
    System.out.println("I am Diana");
}Copy the code

When the program starts, you will see the statements printed in the constructor displayed on the console

This means that after the container is started and the class is loaded into the container, an object will be instantiated. This leads to another conclusion: once the container is initialized, the bean is instantiated

Lazy injection of objects

As mentioned above, the container will instantiate the object (i.e. bean) once it is identified. Is there a way to prevent it from instantiating immediately?

Spring provides the @lazy annotation to indicate that a bean can be lazily loaded.

@Component @Lazy public class Diana{ private String skillName = "Diana R"; public Diana() { System.out.println("I am Diana"); } public void q(){ System.out.println("Diana Q"); } public void w(){ System.out.println("Diana W"); } public void e(){ System.out.println("Diana E"); } public void r(){ System.out.println(this.skillName); }}Copy the code

When you start the program again, the console will still execute the print statement in the constructor. Lazy loading has already been added.

A spring mechanism is designed here to say that if lazy loading is not set for a bean, it will be instantiated at container startup and all other beans that depend on it will be instantiated, even if lazy loading is set.

We used it in the BannerControllerDianaThis bean is lazy loaded, but the BannerController is not lazy loaded, so the container instantiates the BannerController as wellDianaThis bean is instantiated. If you really want to lazy-load, you need to make the BannerController lazy-load too. Add @lazy to it and let’s see:

At this point, the control does not have the output of the print statement, and when we access the route of the BannerController through the browser, we print the output of the statement in the console output constructor.

Object injection logic

Diana’s above is a separate class without any interface. This kind of implementation is problematic and difficult to extend. Instead of a specific implementation class, we should rely on abstraction, so as to meet the open and closed principle and make the program have good expansibility.

This is where Diana implements a Skill interface,

public interface Skill {
    void q();
    void w();
    void e();
    void r();
}Copy the code

The BannerController injection also needs to be changed here:

@Autowired
private Skill diana;Copy the code

Run the program, the first can run successfully, if a new hero implementation class is added:

@Component public class Irelia implements Skill { public Irelia() { System.out.println("Hello, Irelia"); } public void q(){ System.out.println("Irelia Q"); } public void w(){ System.out.println("Irelia W"); } public void e(){ System.out.println("Irelia E"); } public void r(){ System.out.println("Irelia R"); }}Copy the code

When we run the program again, we find that it still runs successfully, and we find that Diana is injected instead of Irelia, so we may ask why.

Private Skill Diana; Does it say Diana here? This is why spring’s injection mechanism is involved.

When Spring’s IOC container injects beans, if it finds multiple beans of the same type, it looks at their name and, if the name is correct, it injects the bean with that name. Each bean scanned by the container will have a default name, its class name, with the first letter lowercase, as in our example: BannerController name is BannerController, Irelia is Irelia.

You can change private Skill Diana to private Skill Skill.

You can’t find the responding bean. Just to be clear, this is standard, but it’s not standard to write the implementation name.

So how do you solve this unfound problem?

Spring provides an annotation for @qualifier, which specifies the bean to inject by passing in the name of the bean to inject, @qualifier (“irelia”).

conclusion

Autowired has two types of injection, one by type and one by name. By default, injection is by type. If you have only one implementation class Diana, which is written as private Skill, and run the program, you will find that injection can be successful. Since there is only one implementation class under the Skill type, it is natural to inject it. If there are more than one implementation class, the system will first search according to the type, and then search according to the name of all the implementation classes under this type, until it finds the one that meets the requirements. If it cannot find, an error will be reported.

For more information on Spring IOC, see [www.immortalp.com]