[JAVA] Understand DI

What is DI

Dependency injection. Instead of creating an instance of the dependent class in the dependent class Make the dependent class have a dependent class as a field variable of the dependent class. Therefore, pass the dependent class from the outside in the constructor etc. Get used to it rather than learn it.

DI process

There are many annotations related to DI, but it is easy to understand if you think that they are basically classified into one of the following three stages. What are the three stages of DI?

--Definition of class to be registered in DI container --Registration to DI container --Injection from DI container

Is.

Definition of class to be registered in DI container

--Defined by Java (= JavaConfig) --Definition by annotation -(Definition by xml) <-I don't do much these days

Definition in Java

Called JavaConfig. --Create a class with @Configuration annotation --Create a method with @Bean annotation

@Configuration
public class AppConfiguration {

  //Register ServiceImpl class in DI container
  @Bean 
  public Service service() {
    return new ServiceImpl();
  }

  //Register RepositoryImpl class in DI container
  @Bean 
  public Repository repository()  {
    return new RepositoryImpl();
  }
  //The same applies below
  .
  .
  .
}

Is it normal to define an interface and put the implementation class in @Configuration?

Definition by annotation

--Add @Component annotation to the registered class. --The @Component annotation is included in the definitions of various annotations. (-> @Controller, @Service, @Repository, @Configuration, etc.)

//@Component annotation@Included in Service annotation
@Service 
public class ServiceImpl implements Service {
}

Registration to DI container

** Actually ** register the instance in the DI container. By performing ** component scan **, you can register the instance in DI.

Component scan with JavaConfig

-Add @ComponentScan annotation to the class with @Configuration annotation --Basically, it scans under the current directory, but if you want to specify it, specify the basePackages attribute. --If you want to specify the scope, add an attribute to the @Scope annotation-> (singleton (default), prototype, request, session)

@Configuration
@ComponentScan(basePackages = "jp.co.yahoo")
// @ComponentScan <-If it is less than the current directory
public class AppConfiguration {
}

Injection from DI container

Add @Autowired annotation. There are the following three methods.

--Constructor injection --Field injection --Setta injection

Constructor injection

Add @Autowired to the constructor.

--The target field can be finalized (= prohibiting the replacement of dependent instances during execution) -You can omit the description of @Autowired

There is a merit. Recommended method.

private final Service service; 
public Controller(Service service) {
  this.service = service; 
}

Field injection

@Autowired
private Service service;

Setter injection

private Service service;
@Autowired
public void setService(Service service) {
  this.service = service; 
}

Only God @SpringBootApplication

@SpringBootApplication annotation may be added when the application is started. If you have this, many of the above annotations will be done without permission. We'll look at that process below.

reference

Many Spring Boot developers always have their main class annotated with @Configuration, @EnableAutoConfiguration and @ComponentScan. Since these annotations are so frequently used together (especially if you follow the best practices above), Spring Boot provides a convenient @SpringBootApplication alternative.

The @SpringBootApplication annotation is equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan with their default attributes:

package com.example.myproject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Preparation 1: About Auto Configuration

** SpringBoot has a predefined JavaConfig class. ** ** If you think about it, this is natural. It cannot be called a framework if it is necessary to define the DI target class every time an external library is added and repeat the work of registering it in the DI container.

The function to automatically register the instance defined in this class in the DI container is called ** AutoConfiguration **.

Conditions registered in the DI container by AutoConfiguration

--Auto-configuration enabled --Dependent library is specified in pom.xml --In the developer's own JavaConfig, the instance defined in the pre-existing JavaConfig has not been redefined.

** Auto-configuration can be enabled by creating a class with the @EnableAutoConfiguration annotation. ** ** In general, add the @EnableAutoConfiguration annotation to a class that has been annotated with @Configuration.

Preparation 2: Start Spring Boot

There are two points in creating an application launch class.

-Add @SpringBootApplication annotation --Execute the run method of @SpringApplication class

@SpringBootAnnotation contains the following annotations.

You can also specify which packages to scan using the scanBasePackages attribute.

@SpringBootApplication(scanBasePackages = "com.example")

Conclusion

By adding @SpringBootApplication annotation, default JavaConfig definition and registration in DI container can be omitted.

When registering by yourself (when adding the difference from the default JavaConfig), if you only define by annotation, you can register to the DI container just by adding @Component annotation, and you can inject with @Autowired annotation. ..

Supplement

――If the difference is too big, you will have to define JavaConfig by yourself, but at present, it is only defined by annotation. --When defining with annotation, component scan will be automated with @SpringBootApplication annotation, so the class to which @Component annotation should be added must be under the current directory of the execution class.

(Well, I think you don't need to be very conscious of it because the execution class is placed at the top level.)

Recommended Posts

Understand DI
Understand Docker
Let's understand closures!
Understand java constructor
[Java] Spring DI ③