Inversion of Control (IOC)/Dependency Injection (DI)

  1. What control has been reversed?

    Inversion of Control is a design idea in which our Control of an object is reversed. We hand over control of the object to Spring’s container.

  2. What is a Spring container?

    Simply put, the Spring container is a mega-factory that creates and manages all the Java objects, called beans. The Spring container manages the dependencies between beans in the container, and Spring uses an approach called dependency injection to manage the dependencies between beans.

  3. What is dependency injection?

    Dependency injection (DI) is an implementation of inversion of control and can be used as an implementation of inversion of control. The Spring container also manages beans in this way. Dependency injection is passing instance variables into an object.

  4. How does the Spring container manage these beans for you?

    Factory mode.

  5. What is the benefit of the Spring framework going to all the trouble of creating a Spring container to manage these beans for us?

The benefits of the factory model are similar:

  • Hard coding coupling is removed, which is conducive to project upgrade and maintenance.
  • Simplifying object management allows us to focus more on business operations

The BeanFactory and ApplicationContext

The relationship between BeanFactory and ApplicationContext

  • BeanFactory and ApplicationContext are Spring’s two core interfaces, and ApplicationContext is a subinterface of BeanFactory. Both can be thought of as containers for Spring, which is a factory that generates Bean instances and manages the beans in the container. In spring-based Java EE applications, all components are treated as beans, including data sources, Hibernate’s SessionFactory, transaction managers, and so on.

  • In life we usually called the place “for the production of products factory, bean object in here is the official name the BeanFactory, literal translation bean plant (com. Springframework. Beans. Factory. The BeanFactory), We call the BeanFactory the IoC container and the ApplicationContext the ApplicationContext.

  • The core of Spring is containers, and containers are not unique. The framework itself provides implementations of many containers, which fall into two categories:

    • One is the less commonly used BeanFactory, which is the simplest container and provides only basic DI functionality.
    • One is the ApplicationContext, derived from the BeanFactory, which provides more enterprise-level services.
      • All Singletons are initialized by default or can be uninitialized by configuration.
      • Inheriting MessageSource, thus enabling internationalization.
      • Resource access, such as access to urls and files.
      • Event mechanism.
      • Load multiple configuration files simultaneously.
      • Start and create the Spring container declaratively.
  • BeanFactory and ApplicationContext both support the use of BeanPostProcessor and BeanFactoryPostProcessor, but the difference between them is: BeanFactory needs to be registered manually, whereas ApplicationContext is automatically registered.

Introduce the BeanFactory

The most basic interface of the Spring container is the BeanFactory. The BeanFactory, the heart of Spring, is responsible for configuring, creating, and managing beans. It is the true face of the Spring IoC container. Spring uses the BeanFactory to instantiate, configure, and manage beans.

The realization of the spring Ioc container, from the source is the beanfactory, but really can as a can be used independently of the Ioc container or DefaultListableBeanFactory, so you can say so, DefaultListableBeanFactory is the ancestor of the spring ioc.

ApplicationContext introduction

If the BeanFactory is the heart of Sping, the ApplicationContext is the entire body.

ApplicationContext common implementation classes:

  • AnnotationConfigApplicationContext: from one or more configuration based on Java class loading context definition, apply to the way Java annotations.
  • ClassPathXmlApplicationContext: from the classpath of one or more XML configuration file loaded context definition, apply to the XML configuration.
  • FileSystemXmlApplicationContext: from the file system under one or more XML configuration file loaded context definition, that is to say, in the system drive load XML configuration files.
  • AnnotationConfigWebApplicationContext: for web applications, suitable for comments.
  • XmlWebApplicationContext: from the web application under one or more of the XML configuration file loaded context definition, suitable for XML configuration mode.

Bean instantiation time & dependency injection time

In Spring, the job of creating an instance of the called is no longer left to the caller. Hence the term inversion of control (IOC). The Spring container does the job of creating the instance of the called and then injecting the caller. So also called dependency injection, when is the bean instantiated? When does dependency injection happen?

When is the bean instantiated

  1. If we use BeanFactory as the factory class for Spring beans, then all beans are instantiated the first time we use the Bean(call getBean()), and we won’t be able to detect some of the existing Spring configuration issues. If a property of the Bean is not injected, the BeanFacotry load does not throw an exception until the first use of the getBean method.

  2. If you use ApplicationContext as the factory class of your Spring Bean, you fall into the following situations:

  • If the scope of the bean is Singleton and lazy-init is false, the ApplicationContext is instantiated when it is started and the instantiated bean is placed in a map cache. The next time you use the Bean, fetch it directly from the cache
  • If the scope of the bean is singleton and lazy-init is true or set to lazy-loaded mode using the @lazy annotation, let the container preinstantiate when resolving the registered bean definition to trigger dependency injection.
  • If the scope of the bean is prototype, the instantiation of the bean is instantiated when the bean is first used

Note: Since the ApplicationContext pre-initializes all Singleton beans, there is a significant overhead during system creation, but once the ApplicationContext is initialized, The program will perform better later when it gets the Singleton Bean instance. You can also set the lazy-init property to true for the bean or use the @lazy annotation, which means that the Spring container will not pre-initialize the bean.

The time when dependency injection occurs

Once the Spring IoC container has located, loaded, and parsed the Bean definition resource, the IoC container is ready to manage the Bean definition data. However, the IoC container has not yet performed dependency injection (DI) on managed beans. Dependency injection occurs in two cases:

  1. The first time a user invokes the getBean() method, the IoC container triggers dependency injection.
  2. Dependency injection is triggered when a user configates a < bean > element in a configuration file with lazy-init=false (the default is false, so you don’t need to set it) or @lazy (false), which causes the container to pre-instantiate when resolving the registered bean definition.

You can see if Bean instantiation and dependency injection are slightly similar in time, which is listed here for reference.

Dependency injection

  1. Interface injection

The interface injection pattern is not favored and has limited practical use because it is intrusive and requires components to be associated with a particular interface.

public class ClassA {  
  private InterfaceB clzB;  
  public void doSomething() {  
    Ojbect obj = Class.forName(Config.BImplementation).newInstance();  
    clzB = (InterfaceB)obj;  
    clzB.doIt();   
  }  
……  
}
Copy the code

To explain the above part of the code, ClassA depends on the implementation of InterfaceB. How do we get an implementation instance of InterfaceB? The traditional approach is to create an instance of the InterfaceB implementation class in code that will be assigned to clzB. In this way, ClassA relies on InterfaceB’s implementation at compile time. To separate the caller from the implementer at compile time, the above code is created. We dynamically load the implementation class according to the name of the implementation class set in the configuration file (config.bimplementation), and force the transformation through InterfaceB for use by ClassA. This is the most primitive prototype of interface injection. Setter method injection

Setter injection patterns are widely used in practical development. Setter methods are more intuitive. Let’s take a look at the Spring configuration file:

<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd "> <! Using Spring to manage object creation, And object dependencies - > < bean id = "userDao4Mysql" class = "com. The TGB. Spring. Dao. UserDao4MysqlImpl" / > < bean id = "userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <! Ioc automatically creates the corresponding userDao implementation, which is container-managed --> <! -- (2) Provide a constructor in UserManager that lets Spring inject the UserDao implementation (DI) --> <! Let Spring manage the creation and dependencies of our objects Dependencies must be configured into the spring core configuration file --> <property name="userDao" ref="userDao4Oracle"></property> </bean> </beans>Copy the code
  1. Setter method injection
import com.tgb.spring.dao.UserDao; public class UserManagerImpl implements UserManager{ private UserDao userDao; Public void setUserDao(UserDao UserDao) {this. UserDao = UserDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); }}Copy the code
<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd "> <! Using Spring to manage object creation, And object dependencies - > < bean id = "userDao4Mysql" class = "com. The TGB. Spring. Dao. UserDao4MysqlImpl" / > < bean id = "userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <! Ioc automatically creates the corresponding userDao implementation, which is container-managed --> <! -- (2) Provide a constructor in UserManager that lets Spring inject the UserDao implementation (DI) --> <! Let Spring manage the creation and dependencies of our objects Dependencies must be configured into the spring core configuration file --> <property name="userDao" ref="userDao4Oracle"></property> </bean> </beans>Copy the code
  1. Constructor injection
import com.tgb.spring.dao.UserDao; public class UserManagerImpl implements UserManager{ private UserDao userDao; Public UserManagerImpl(UserDao UserDao) {this. UserDao = UserDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); }}Copy the code

Some articles also mention methods such as factory method injection, which will not be explained here

assembly

You can’t talk about dependency injection without talking about assembly. The essence of DEPENDENCY injection is assembly, and assembly is the specific behavior of dependency injection.

Spring is extremely flexible and provides three main assembly mechanisms:

  1. Display configuration in XMl: Load the configuration into the IOC container through an XMl file

  2. Display configuration in Java: Load the configuration into the IOC container via Java annotations

@configuration public class ManConfig {@bean public Man Man() {return new Man(car()); } @Bean public Car car() { return new QQCar(); }}Copy the code
  1. Implicit bean discovery mechanisms and autowiring
    • Component Scanning (@ComponentScan&@Configuration) : Spring automatically discovers beans created in the application context.
    • Autowiring (@AutoWired &@Resource(@Qualifier)&@Value) : Spring automatically satisfies dependencies between beans.

Implicit bean discovery mechanisms and autowiring

/** * This is an implementation of a game disc */ // This simple annotation indicates that the class is back as a component class and tells Spring to create a bean for it. @component public class GameDisc implements Disc{@override public void play() {system.out.println (" I am XXX GameDisc." ); }}Copy the code

However, component scanning is disabled by default. We also need to explicitly configure Spring to find the @Component annotated class and create a bean for it.

@Configuration
@ComponentScan
public class DiscConfig {
}
Copy the code

We added an @ComponentScan annotation to DiscConfig to indicate that component scanning is enabled in Spring. By default, the same package as the configuration class is scanned to scan the GameDisc Bean. This is Spring’s autowiring mechanism.

The life cycle of the Bean

Here we are talking about the life cycle of the Bean in ApplicationContext. The BeanFactory is similar, but the handler needs to be manually registered.

Bean life cycle:

In the book, the methods that may be called during the whole life cycle of a bean are divided into four categories:

  1. The Bean’s own methods. Constructors, getters, setters, other custom methods

  2. Bean-level lifecycle methods. To invoke these methods, the Bean implements the bean-level lifecycle method interface: Such as BeanNameAware BeanFactoryAware, InitializingBean DisposableBean, the method of these interfaces is invoked automatically, scope only for interface implements the above four types of beans

  3. Container-level lifecycle interface methods. Methods with ☆ in the figure are container-level methods. All beans in a container are handled by container-level lifecycle methods, and the interface at this level is implemented separately, independent of the bean. Pictured above containers and lifecycle interface for: InstantiationAwareBeanPostProcessor and BeanPostProcessor

  4. Factory after processor interface methods: including AspectJWeavingEnabler, CustomeAutowireConfigurer, ConfigurationClassPostProcessor method, called immediately after the application context assembly file

This article combines many big guy’s blog post, don’t ask why don’t write, tired ~ ~, hope to solve some doubts of you

Recommended articles:

  • Understand the Spring container, BeanFactory, and ApplicationContext
  • Spring Bean lifecycle (very detailed)
  • There are three dependency injection methods in Spring IOC