What Is Inversion of Control?
Inversion of Control is a principle in software engineering which transfers the control of objects or portions of a program to a container or framework.
在 Spring 中,类的实例化、依赖的实例化、依赖的传入都交由 Spring Bean 容器控制, 而不是用new方式实例化对象再通过非构造函数方法传入依赖等常规方式。 实质的控制权已经交由程序管理,而不是程序员管理,所以叫做控制反转。
We can achieve Inversion of Control through various mechanisms
such as:
- Strategy design pattern,
- Service Locator pattern,
- Factory pattern,
- Dependency Injection (DI).
What Is Dependency Injection?
Dependency injection is a pattern we can use to implement IoC.
Connecting objects with other objects, or “injecting” objects into other objects, is done by an assembler rather than by the objects themselves.
Spring 启动时会把所需的类实例化成对象,如果需要依赖,则先实例化依赖,然后实例化当前类。 因为依赖必须通过构建函数传入,所以实例化时,当前类就会接收并保存所有依赖的对象。 这一步也就是所谓的依赖注入。
Here’s how we would create an object dependency in traditional programming:
public class Store {
private Item item;
public Store() {
item = new ItemImpl1();
}
}
By using DI, we can rewrite the example.
public class Store {
private Item item;
public Store(Item item) {
this.item = item;
}
}
The Spring IoC Container
In the Spring framework, the interface ApplicationContext represents the IoC container. The Spring container is responsible for instantiating, configuring and assembling objects known as beans, as well as managing their life cycles.
Dependency Injection in Spring can be done through constructors, setters or fields.
Constructor-Based Dependency Injection
In the case of constructor-based dependency injection, the container will invoke a constructor with arguments each representing a dependency we want to set.
Let’s see the configuration of a bean and its dependencies using annotations:
class AppConfig {
public Item item1() {
return new ItemImpl1();
}
public Store store() {
return new Store(item1());
}
}
public
We use the @Bean annotation on a method to define a bean. If we don’t specify a custom name, then the bean name will default to the method name.
Another way to create the configuration of the beans is through XML configuration:
<bean id="item1" class="org.baeldung.store.ItemImpl1" />
<bean id="store" class="org.baeldung.store.Store">
<constructor-arg type="ItemImpl1" index="0" name="item" ref="item1" />
</bean>
Setter-Based Dependency Injection
For setter-based DI, the container will call setter methods of our class after invoking a no-argument constructor or no-argument static factory method to instantiate the bean.Let’s create this configuration using annotations:
Store store() {
Store store = new Store();
store.setItem(item1());
return store;
}
public
We can also use XML for the same configuration of beans:
<bean id="store" class="org.baeldung.store.Store">
<property name="item" ref="item1" />
</bean>
We can combine constructor-based and setter-based types of injection for the same bean. The Spring documentation recommends using constructor-based injection for mandatory dependencies, and setter-based injection for optional ones.
Field-Based Dependency Injection
In case of Field-Based DI, we can inject the dependencies by marking them with an @Autowired annotation:
public class Store {
private Item item;
}
While constructing the Store object, if there’s no constructor or setter method to inject the Item bean, the container will use reflection to inject Item into Store.
Autowiring Dependencies
There are four modes of autowiring a bean using an XML configuration:
- no: the default value – this means no autowiring is used for the bean and we have to explicitly name the dependencies.
- byName: autowiring is done based on the name of the property, therefore Spring will look for a bean with the same name as the property that needs to be set.
- byType: similar to the byName autowiring, only based on the type of the property. This means Spring will look for a bean with the same type of the property to set. If there’s more than one bean of that type, the framework throws an exception.
- constructor: autowiring is done based on constructor arguments, meaning Spring will look for beans with the same type as the constructor arguments.
参考:
Intro to Inversion of Control and Dependency Injection with Spring