Spring IoC container details

Posted by Blaze(!) on Thu, 16 Jan 2020 11:23:43 +0100

Dependent processing

The process of container solving dependency

  • ApplicationContext is created and initialized through configuration metadata, which describes all bean s. Configuration metadata can be XML, java code and annotation
  • For each bean, its dependency is expressed in the form of an attribute, constructor parameter, or parameter of a static factory method (if not a normal constructor). When the bean is actually created, its dependency is provided
  • Each property or constructor parameter is set to an actual value or to reference other beans in the bean container
  • The value of each property or constructor parameter is converted to the actual type of the property or constructor parameter according to the description information. By default, Spring can convert the value in a string format to all built-in types, such as int,long,String,boolen, etc
    The Spring container verifies the configuration of each Bean when the container is created. However, before the Bean is actually created, the Bean property itself will not be set. When the container is created, the single Bean is instantiated in advance (by default). The scope is defined in the Bean scope. Otherwise, the Bean is created only when it is requested. Creating a Bean may cause a series of beans to be created, because Dependencies for beans and their dependencies (and so on) are created and allocated. Note that late processing of dependency mismatches will be explained
Cyclic dependency

If you mainly use constructor injection, you may encounter a loop dependency scenario that cannot be resolved. For example, class a needs an instance of class B, which is injected through the constructor. Class B needs an instance of class A, which is also injected through the constructor. If the beans of class A and class B are configured to inject each other, the Spring IoC container will detect this loop reference at run time and introduce Send a BeanCurrentlyInCreationException

The solution is to modify the code, configure it as setter method injection instead of constructor injection, or avoid constructor injection and only use setter method injection. In short, use setter method injection to configure a circular dependency

Unlike the typical case (no circular dependency), the circular dependency between bean A and bean B forces one bean to inject another before it is fully initialized (classic chicken / egg scenario)

You can believe that spring can handle things correctly. It will detect configuration problems when the container loads, such as referencing nonexistent beans, circular dependency. When spring creates beans, set property values and resolve dependencies as late as possible. This means that a properly loaded spring container will also generate exceptions when it requests an object, if it creates this object or For example, when the property value is missing or illegal, the bean will throw an exception. Some configuration problems are found to be delayed because the default implementation of ApplicationContext instantiates the singleton bean in advance. Before these beans are actually needed, in order to create these beans, it takes a certain amount of time and memory. You will find configuration problems when ApplicationContext is created, and No later. You can override the default implementation, so that the singleton bean will delay instantiation instead of pre instantiation
If there is no circular dependency, one or more collaboration beans are fully configured before being injected into a dependency Bean. This means that if there is a Bean that depends on Bean B, the container has fully configured Bean B before calling Bean a's setter method. In other words, the Bean is initialized, its dependency is set, and the related life cycle method will be called

Dependency injection example

The following is an example of dependency injection based on setter method

<bean id="exampleBean" class="example.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
    <ref bean="anotherExampleBean"/>
</property>

<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {    
private AnotherBean beanOne;
private YetAnotherBean beanTwo;

private int i;

public void setBeanOne(AnotherBean beanOne) {
    this.beanOne = beanOne;
}

public void setBeanTwo(YetAnotherBean beanTwo) {
    this.beanTwo = beanTwo;
}

public void setIntegerProperty(int i) {
    this.i = i;
}
}

The previous example is that the setters method is declared to match the properties specified in the XML file. The following example is based on the constructor dependency injection

<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
    <ref bean="anotherExampleBean"/>
</constructor-arg>

<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>

<constructor-arg type="int" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

private AnotherBean beanOne;

private YetAnotherBean beanTwo;

private int i;

public ExampleBean(
    AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
    this.beanOne = anotherBean;
    this.beanTwo = yetAnotherBean;
    this.i = i;
}
}

The constructor Arg described in the bean definition will be used as a parameter of the ExampleBean constructor
Instead of using constructors, use static factory methods to return an instance object

<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

// a private constructor
private ExampleBean(...) {
    ...
}

// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
    AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {

    ExampleBean eb = new ExampleBean (...);
    // some other operations...
    return eb;
}
}

To provide parameters for static factory methods to pass through elements is like using constructors in practice. The type returned by static factory methods is not the same as the class of static factory methods, although our example is like this. Instance (non static) factory methods will be used in the same way as the base (except for using factory bean properties instead of class properties), So we won't discuss the details here

Published 3 original articles, praised 0, visited 84
Private letter follow

Topics: Spring Attribute xml Java