SpringSpring IOC & DI

Spring IOC & DI

  • Getting Started with IOC DI
    • What is Spring
      • What is a container
      • What is IOC
    • Introduction to IOC
      • traditional program development
      • solution
    • DI
  • Detailed explanation of IOC
    • Bean storage
      • @Controller(controller storage)
      • @Service(service storage)
      • @Repository(warehouse storage)
      • @Component(component storage)
      • @Configuration(configuration storage)
    • Why do we need so many class annotations?
    • Relationship between class annotations
    • Method annotation @Bean
      • Define multiple objects
    • Rename Bean
    • scan path
  • Detailed explanation of DI
    • Property injection
    • Constructor injection
    • Setter injection
    • Analysis of the advantages and disadvantages of three types of injection
    • @Autowired there is a problem
      • @Primary
      • @Qualifier
      • @Resource

Introduction to IOC DI

What is Spring

Spring is an open source lightweight Java development framework that provides comprehensive infrastructure support and a wide range of application-level features, making Java development simpler and more efficient. The core features of the Spring framework include dependency injection (Dependency Injection), aspect-oriented programming (AOP), containers, transaction management, etc.

Dependency injection allows developers to externalize dependencies between components, which reduces the coupling between classes and makes the code easier to maintain and test. Aspect-oriented programming allows developers to define cross-cutting concerns, such as logging, transaction management, etc., thereby achieving modular development.

The Spring framework also provides a lightweight IoC container for managing the life cycle and configuration of JavaBeans. In addition, Spring also supports a variety of application-level features, including web development, data access, security, remote calling, etc.

In general, the Spring framework plays an important role in Java enterprise application development. It provides rich functions and flexible design concepts, allowing developers to write maintainable and scalable applications more efficiently.

What is a container

A container is a (basic) device for holding something.
?Living cups, trash cans, refrigerators, etc. are all containers.

? List/Map -> Data storage container
? Tomcat -> Web container

What is IOC

IOC (Inverse of Control)is a design principle in object-oriented programming. It is an implementation method of dependency injection (DI) in software development. In IOC, control is transferred from traditional application code to an external container or framework, so that dependencies between objects are managed and injected externally.

In the traditional programming model, an object usually directly creates and manages other objects on which it depends. In an IOC container, the object’s dependencies are injected by the container when the object is created, not by the object itself. This transfer of control reduces the coupling between objects and is more conducive to code testability and maintainability.

The Spring framework is a typical IOC container, which manages dependencies between objects through dependency injection. Developers only need to describe the dependencies between components, such as through configuration files or annotations, and the Spring container is responsible for instantiating the objects and injecting the dependencies between them.

In general, IOC makes the system more flexible and scalable by externalizing the dependencies between objects, and helps reduce the coupling between codes.

Introduction to IOC

Next, let’s understand through cases? What is IoC?
Requirements: Build a car?

Traditional program development

Our implementation idea is as follows:
First design the wheels (Tire), then design the chassis (Bottom) according to the diameter of the wheels, then design the framework (Framework) based on the chassis, and finally design the entire car (Car) based on the dimensions. Here comes a “dependence” relationship: the car depends on the engine, the engine relies on the chassis, and the chassis depends on the wheel.


Such a design looks fine, but maintainability is very low

For example, we need to modify the size of the tires because the chassis is made based on the tires, so the size of the chassis also needs to be modified, because the body is made based on the chassis, and the body also needs to be modified, because the entire car is made based on the body, so the entire car also needs to be modified. At this time, we found that if there was a small modification, the whole would be greatly changed and the maintainability was very low

Solution

In the above procedure, we designed the chassis based on the wheel size. If the wheel size changes, the chassis design will have to be modified. Also because we designed the chassis based on the wheel size, the chassis design will also have to be modified. Change, in the same way, the design of automobiles must also be changed, that is, the entire design must be changed~

We try to change our thinking. We first design the concept sample of the car, then design the chassis based on the car sample, design the chassis based on the chassis, and finally design the wheels based on the chassis. At this time, dependencies It’s the other way around: the wheels depend on the chassis, the chassis depends on the wheels, and the wheels depend on the cars.

How to achieve it:

We can try not to create lower-level classes in each class. If we create a lower-level class, it will appear when the lower-level class changes the operation, and it will also be modified accordingly. At this time, we only need to change the original reason The created subordinate class is changed to the passed form (that is, the annotated form). Because we do not need to create a subordinate class in the current class, even if the subordinate class changes (creates or reduces parameters), The current class does not need to modify any code, thus completing the decoupling of the program.

For example, development in this way to achieve decoupling between programs is called IOC program development

IOC Container

As can be seen from the above, IoC containers have the following advantages:
Resources are not managed by both parties who use the resources, but by a third party who does not use the resources, which can bring many benefits. Third, centralized management of resources makes resources configurable and easy to manage. Third, it reduces the dependence on both sides of the use of resources, which is what we call coupling.

  1. Centralized management of resources: The IoC container will help us manage some resources (objects, etc.). When we need to use them, we only need to retrieve them from the IoC container.
    That’s it
  2. We don’t need to know the details when creating an instance, which reduces the dependence on using dual resources, that is, the degree of coupling.
    Spring is an IoC container that helps us manage these resources.

DI

DI: Dependency Injection(dependency injection?)
During the operation of the container, the container dynamically provides the resources that the application depends on during operation, which is called dependency injection.

When the program needs a certain resource when running, the container will provide it with this resource.
From this point of view, dependency injection and inversion of control describe the same thing from different perspectives, which is to achieve decoupling of objects by introducing IOC containers and using dependency injection.
Objects are stored in the ioc container, and we use di to take this object out of the container and use it

Detailed explanation of IOC

The Spring container mainly manages objects, which we call “Beans”. We hand over these objects to Spring for management, and Spring is responsible for the creation and destruction of objects. Our program only needs to tell Spring what needs to be Storage, and how to get objects from Spring

Through the above case, we already know the basic operations of Spring IoC and DI. Next, we will study Spring IoC and DI systematically.
Operation. Earlier, we mentioned IoC control inversion, which is to hand over the control of the object to Spring’s IOC container, and the IOC container creates and manages the object.
elephant. That is, the storage of beans.

Bean storage

In the previous case, if you want to hand over an object to the IOC container for management, you need to add an annotation to the class: @Component
The Spring framework provides richer annotations in order to better serve web applications.

There are two kinds of annotations that can be implemented

  1. Class annotations: @Controller @Service @Repository @Component @Configuration
  2. Method annotation: @Bean

@Controller(controller storage)

import org.springframework.stereotype.Controller;

@Controller
public class UserController {<!-- -->
    public void sayHi(){<!-- -->
        System.out.println("hi UserController");
    }
}

How to observe that this object already exists in the Spring container?
Next learn how to get objects from the Spring container

@SpringBootApplication
public class DemoApplication {<!-- -->

    public static void main(String[] args) {<!-- -->
        //Get the Spring context object
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        //Get the object from the Spring context
        UserController userController = context.getBean(UserController.class);
        //user target audience
        userController.sayHi();
    }
}

The above code searches for objects based on type. If there are multiple beans of the same type in the Spring container, how to obtain them?
ApplicationContext also provides other ways to obtain beans. The function of ApplicationContext to obtain bean objects is a function provided by the class BeanFactory

The first, second and fifth types are commonly used

The first is to obtain the bean based on the bean name
The second is to obtain the bean based on the bean name and type
The fifth method is to dynamically create a bean according to the bean type and constructor parameters. This is only applicable to beans with prototype scope

But the name of the bean involved. So what is the name of the bean?

Bean naming convention
Program developers do not need to specify a name for the bean. If a name is not provided explicitly, the Spring container will generate a unique name for the bean

  1. Naming convention uses the Java standard convention for instance field names, that is, the bean name starts with a lowercase letter and then uses camelCase.
    For example, the class name UserController Bean is named userController.
  2. When there are multiple characters and the first and second characters are both uppercase, the original case will be preserved
    For example, the name of the class name UController Bean is UController

Comparison between ApplicationContext and BeanFactory

  1. In terms of inheritance relationships and functions, the Spring container has two top-level interfaces, BeanFactory and ApplicationContext. BeanFactory provides basic capabilities to access the container, and ApplicationContext is a subclass of BeanFactory. In addition to inheriting all the functions of BeanFactory, it also has unique features, and also adds support for internationalization support, resource access support, and event propagation.
  2. From a performance perspective: ApplicationContext loads and initializes all Bean objects at once, while BeanFactory only loads which ones are needed, so it is more lightweight.

@Service(service storage)

@Service
public class UserService {<!-- -->

    public void sayHi(){<!-- -->
        System.out.println("hi UserService");
    }
}


@Repository (warehouse storage)

@Repository
public class UserRepository {<!-- -->
    public void sayHi(){<!-- -->
        System.out.println("hi UserRepository");
    }
}


@Component (component storage)

@Component
public class UserComponent {<!-- -->
    public void sayHi(){<!-- -->
        System.out.println("hi UserComponent");
    }
}


@Configuration (configuration storage)

@Configuration
public class UserConfiguration {<!-- -->
    public void sayHi(){<!-- -->
        System.out.println("hi UserConfiguration");
    }
}


Why so many class annotations are needed

The class annotations here correspond to the application layering. After seeing the class annotations, programmers can directly understand the purpose of the current class

? @Controller: Control layer, receives requests, processes requests, and responds.
? @Servie: Business logic layer, handles specific business logic.
? @Repository: Data access layer, also called persistence layer. Responsible for data access operations
? @Configuration: Configuration layer. Processes some configuration information in the item

Relationship between class annotations

Looking at the source code of @Controller / @Service / @Repository / @Configuration and other annotations, we found: In fact, these annotations have an annotation @Component, indicating that they are subclasses based on @Component

@Component is a meta-annotation, which means it can annotate other class annotations, such as @Controller, @Service, @Repository, etc. These annotations are called derivative annotations of @Component.

@Controller, @Service and @Repository For more specific examples (respectively in the control layer, business logic layer, persistence layer), during the development process, if you want to use @Component or @Service in the business logic layer, Obviously @Service is a better choice

Method annotation @Bean

Class annotations are added to a class, but there are two problems:

  1. When using an external package class, there is no way to add class annotations.
  2. ?A class requires multiple objects, ?such as multiple data sources
    In this scenario, we need to annotate @Bean using the method
@Component
public class BeanConfig {<!-- -->
    @Bean
    public User user(){<!-- -->
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
}



Method annotations should be used in conjunction with class annotations

Define multiple objects

How to define multiple objects of the same class?

For example, in the scenario of multiple data sources, the class is the same, but the configuration is different and points to different data sources.

@Component
public class BeanConfig {<!-- -->
    @Bean
    public User user1(){<!-- -->
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
    
    @Bean
    public User user2(){<!-- -->
        User user = new User();
        user.setName("lisi");
        user.setAge(20);
        return user;
    }
}

When we define multiple objects, we get the object based on the type. Which object do we get?

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.Model.User' available: expected single matching bean but found 2: user1,user2
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1273)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:494)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1178)
at com.example.demo.DemoApplication.main(DemoApplication.java:35)

We found that the code reported an error at this time. According to the error message, we expected only one match, but found two objects user1 and user2

It can be seen from the error message that the name of the Bean annotated with @Bean is its method name
We can get the Bean object by name

User user1 = (User) context.getBean("user1");
User user2 = (User) context.getBean("user2");
System.out.println(user1);
System.out.println(user2);

Rename Bean

You can rename the Bean object by setting the name attribute.

At this point we can either get the User object through the name user1 or the User object through the name u1

name=can be omitted

When there is only one name, the brackets can also be omitted

Scan path

Will a bean declared with four annotations definitely take effect? The answer is not necessarily because the bean needs to be scanned by Spring in order to take effect

For beans declared using the five major annotations to take effect, you need to configure the scan path so that Spring can scan these annotations

That is, use @ComponentScan to configure the scan path

Why can we scan beans without configuring the scan path before?
Although we have not explicitly configured @ComponentScan, this annotation has been included in the annotation of the startup class

The default scanning scope is the package containing the SpringBoot startup class and its sub-packages

DI detailed explanation

We have explained the details of Inversion of Control IoC above, and now we will introduce the details of DI

Dependency notice is a process that refers to the IoC container providing resources that the operation depends on when creating a bean. Resources refer to objects. In the above program case, we used the @Autowired annotation. The dependency injection operation is completed. To put it simply, it is to take out the object and put it into the attribute of a certain class.

In some chapters, dependency annotation is also called “object annotation” and “property assembly”. The specific meaning needs to be understood in conjunction with the context of the chapter.

Concerning dependency injection, Spring also provides us with three methods

  1. Property injection
  2. Constructor injection
  3. Setter injection

Attribute injection

Property annotation is implemented using @Autowired, and the Service class is injected into the Controller class.
The implementation code of the Service class is as follows:

@Service
public class UserService {<!-- -->

    public void sayHi(){<!-- -->
        System.out.println("hi UserService");
    }
}

Controller class implementation

@Controller
public class UserController {<!-- -->

    @Autowired
    //Inject UserService into Usercontroller
    private UserService userService;
    public void sayHi(){<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
    }
}


Constructor injection

@Controller
public class UserController {<!-- -->
    //Method 2: Constructor method injection
    //Inject UserService into Usercontroller
    private UserService userService;
    @Autowired
    public UserController(UserService userService) {<!-- -->
        this.userService = userService;
    }
    
    public void sayHi(){<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
    }
}

Note: If the class has only one constructor, the @Autowired annotation can be omitted; if there are multiple constructors in the class, then @Autowired needs to be added to clearly specify which constructor to use

Setter injection

Note: If the class has only one constructor, the @Autowired annotation can be omitted; if there are multiple constructors in the class, then @Autowired needs to be added to clearly specify which constructor to use.

@Controller
public class UserController {<!-- -->
    //Method 3: Setter injection
    //Inject UserService into Usercontroller
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {<!-- -->
        this.userService = userService;
    }
    
    public void sayHi() {<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
    }
}

Analysis of advantages and disadvantages of three types of injection

Constructor injection:

Advantages: Constructor injection can guarantee the integrity of the object because it requires that the required property values must be provided when the object is created. This avoids objects being left in an incomplete or inconsistent state. At the same time, constructor injection also allows objects to be immutable after creation.
Disadvantages: Constructor injection will be verbose when there are many parameters, especially when there are many properties and there are dependencies between properties. In addition, for each dependency, a corresponding constructor needs to be provided, which may result in a class with an overly bloated constructor.

Setter method injection:

Advantages: Setter method injection is more flexible to use than constructor method injection, and there is no need to pass all dependencies when creating an object. Properties can be injected one by one by calling individual Setter methods. At the same time, Setter method injection also facilitates subsequent modification or replacement of attribute values.
Disadvantages: Setter method injection destroys the integrity of the object because dependencies can be injected at any time after the object is created. This can cause objects to be in an inconsistent state during certain operations. In addition, it also increases the variability of the class, which may lead to object immutability and thread safety issues.

Field injection:

Advantages: Field injection is simple and intuitive, without lengthy code for constructors or setter methods. For small applications or rapid prototyping, field injection may be more convenient.
Disadvantages: Field injection breaks encapsulation, exposing dependencies directly as public fields. This violates the principles of object-oriented programming and can lead to problems with code maintainability and testability. Additionally, field injection is not conducive to unit testing and mocking dependencies.

There is a problem with @Autowired

When there are multiple beans of the same type, there will be problems using @Autowired

@Controller
public class UserController {<!-- -->
    @Autowired
    private UserService userService;

    @Autowired
    private User user;

    public void sayHi() {<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
        System.out.println(user);
    }
}

The reason for the error is non-unique Bean object
So how to solve the above problems? Spring provides the following solutions

@Primary

Use the @Primary annotation. When there are multiple bean injections of the same type, add the @Primary annotation to determine the default implementation

@Component
public class BeanConfig {<!-- -->
    @Primary
    @Bean("user1")
    public User user1(){<!-- -->
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }

    @Bean
    public User user2(){<!-- -->
        User user = new User();
        user.setName("lisi");
        user.setAge(20);
        return user;
    }
}

@Qualifier

Use @Qualifier annotation: specify the bean object to be annotated currently. In the value attribute of @Qualifier, specify the name of the annotated bean.

@Controller
public class UserController {<!-- -->
    @Autowired
    private UserService userService;

    @Autowired
    @Qualifier("user2")
    private User user;

    public void sayHi() {<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
        System.out.println(user);
    }
}

The @Qualifier annotation cannot be used alone and must be used in conjunction with @Autowired

@Resource

Use @Resource annotation: Annotate according to the name of the bean. Specify the name of the bean to be injected through the name attribute.

@Controller
public class UserController {<!-- -->
    @Autowired
    private UserService userService;

    @Resource(name = "user2")
    private User user;

    public void sayHi() {<!-- -->
        System.out.println("hi UserController");
        userService.sayHi();
        System.out.println(user);
    }
}

The difference between @Autowird and @Resource
? @Autowired is an annotation provided by spring framework, ?@Resource is an annotation provided by JDK
? @Autowired is annotated by type by default, and @Resource is annotated by name

syntaxbug.com © 2021 All Rights Reserved.