IO /spring-fram…

1.4 depend on

A typical enterprise application is not composed of a single object (or bean, in Spring parlance). Even the simplest application has some objects that work together to present what the end user thinks is a consistent application. This section explains how to move from defining a large number of independent bean definitions to a fully implemented application in which objects collaborate to achieve goals.

1.4.1 Dependency Injection

Objects can only define their dependencies through constructors, arguments to factory methods, or set methods, which are injected by the container when the bean is created. This process is basically the reverse of a bean directly calling a new method or a mechanism such as the Service Locator pattern to control the instantiation of its dependencies (hence the name “inversion of control”).

Using dependency injection code is clearer, and decoupling is more effective when objects are supplied with their dependencies. The object does not look up its dependencies, nor does it know the location or class of the dependencies. As a result, your classes become easier to test, especially when the dependencies are interfaces or abstract classes, which allows mock implementations to be used in unit tests.

Dependency injection exists in two cases: constructor-based dependency injection and setter-based dependency injection.

Constructor-based dependency injection

Construction-based injection is done by the container calling the constructor with parameters, each representing a dependency. Calling a static factory method with specific parameters to construct a bean is almost equivalent to a constructor, and this article treats constructor arguments and static factory method arguments in a similar way. The following example shows a class that can only be injected through constructor injection:

public class SimpleMovieLister { // the SimpleMovieLister has a dependency on a MovieFinder private final MovieFinder movieFinder; // a constructor so that the Spring container can inject a MovieFinder public SimpleMovieLister(MovieFinder movieFinder)  { this.movieFinder = movieFinder; } // business logic that actually uses the injected MovieFinder is omitted... }Copy the code

There is nothing special about this class. It is a POJO that does not depend on container-specific interfaces, base classes, or annotations.

Constructor parameter parsing

Constructor parameter resolution matching is implemented by using the type of the parameter. If there is no potential ambiguity in the constructor parameters of the bean definition, the order in which the constructor parameters are defined in the bean definition is to supply them to the appropriate constructor when the bean is instantiated. Consider the following classes:

package x.y; public class ThingOne { public ThingOne(ThingTwo thingTwo, ThingThree thingThree) { // ... }}Copy the code

Assuming there is no inheritance between the ThingTwo and ThingThree classes, there is no potential ambiguity. Therefore, the following configuration works and does not require an explicit constructor parameter index or type to be specified in the element.

<beans>
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg ref="beanTwo"/>
        <constructor-arg ref="beanThree"/>
    </bean>

    <bean id="beanTwo" class="x.y.ThingTwo"/>

    <bean id="beanThree" class="x.y.ThingThree"/>
</beans>
Copy the code

In the case above, the dependency is a bean whose type is known and spring can match it. But when using simple types, such as true, Spring cannot determine the type of the value, so it cannot match by type without help. Consider the following classes:

package examples; public class ExampleBean { // Number of years to calculate the Ultimate Answer private final int years; // The Answer to Life, the Universe, and Everything private final String ultimateAnswer; public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }}Copy the code

Matches by parameter type

In the previous scenario, if the type attribute is used to explicitly specify the type of the constructor parameter, the container can use type matching of simple types, as shown in the following example:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>
Copy the code

Match by parameter subscript

You can explicitly specify the index of the constructor argument using the index attribute, as shown in the following example:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>
Copy the code

In addition to resolving the ambiguity of multiple simple values, specifying an index resolves the ambiguity of a constructor having two parameters of the same type.

Note: Subscripts start at 0

Match by parameter name

You can also use constructor parameter names to disambiguate values, as in the following example:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>
Copy the code

Keep in mind that for this to work, your code must compile with the debug flag enabled so that Spring can get the parameter names from the constructor. If you can’t or don’t want to compile code with debug flags, you can use the @ConstructorProperties JDK annotation to explicitly name the constructor parameters. The sample class should look like this:

package examples; public class ExampleBean { // Fields omitted @ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }}Copy the code

Dependency injection based on Setter methods

Setter-based dependency injection is done by the container calling setter methods on the bean after invoking the parameterless constructor or parameterless static factory methods to instantiate the bean.

The following example shows a class that can only be injected through dependency injection using pure setter injection. This class is a traditional POJO class that doesn’t depend on container-specific interfaces, base classes, or annotations.

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...
}
Copy the code
<bean id="exampleBean" class="examples.SimpleMovieLister">
    <property name="movieFinder" ref=movieFinder/>
</bean>
Copy the code

ApplicationContext supports construction-based and setter-based dependency injection for the beans it manages. It also supports setter-based dependency injection after injecting some dependencies through constructor methods. You can configure dependencies as BeanDefinitions. But most Spring users do not configure programmatically, using XML Bean definitions, annotated components (that is, annotated classes like @Component and @Controller), or the @Bean method in the Java-based @Configuration class. These sources are then internally converted to instances of BeanDefinition and used to load the entire Spring IoC container instance.

Because you can use a mixture of constructor-based and setter-based dependency injection, it is a good rule of thumb to use constructors for mandatory dependencies and setter or configuration methods for optional dependencies. Note that using the @required annotation on setter methods makes this property a Required dependency; However, it is preferable to inject dependencies using constructors that programmatically validate parameters.

The Spring team generally advocates constructor injection because it allows you to implement application components as immutable objects and ensure that required dependencies are not null. In addition, constructor-injected dependencies are always returned to the client code in the fully initialized state. By the way, a large number of constructor arguments is a bad code smell, meaning that classes may have too many responsibilities and should be refactored to better address the proper separation of concerns.

Setter injection is primarily used for optional dependencies that can be assigned reasonable defaults in the class, otherwise non-null checks must be performed wherever the code uses the dependency. One benefit of setter injection is that setter methods enable objects of that class to be reconfigured or reinjected later.

Use the dependency injection style that makes the most sense for a particular class. Sometimes, when you work with third-party classes that don’t have source code, you can choose your own injection method; If a third-party class does not expose any setter methods, constructor injection may be the only form of DI available.

Depend on the process of parsing

The container performs bean dependency resolution as follows:

  • Create and initialize the ApplicationContext based on the bean’s configuration metadata. Configuration metadata can be specified through XML, Java code, or annotations.

  • For each bean, its dependencies are expressed as constructor parameters or static factory method parameters. These dependencies are provided to the bean when it is actually created.

  • Each property or constructor parameter is either the actual value or a reference to another bean in the container.

  • An attribute or constructor parameter that is a setting value rather than a reference is converted from its specified format to the actual type of the attribute or constructor parameter. By default, Spring converts values supplied in string format to all actual type types, such as int, Long, String, Boolean, and so on.

The Spring container validates the configuration of each bean when the container is created. However, the bean property itself is not set until the bean is actually created. Beans configured to singleton-scoped (the default) are instantiated when the container is created, otherwise they are only created when the bean is requested. Creating a bean may result in creating a bean chain because the bean has dependencies and their dependencies (and so on). Note that parsing mismatches between these dependencies can occur at a later stage — that is, when the affected bean is first created.

Circular dependencies

If you use constructor injection primarily, you can create non-resolvable cyclic dependency scenarios.

For example, class A needs an instance of class B via constructor injection, and class B needs an instance of class A via constructor injection. If you will be class A and class B bean is configured to into each other, so the Spring IoC container will detect the circular reference at runtime, and throw beancurcurrentlyincreationexception.

One possible solution is injection by setters. Avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies using setter injection.

Unlike the typical case (where there are no cyclic dependencies), a cyclic dependency between Bean A and Bean B forces one bean to be injected into another bean before fully initializing itself (a typical chicken-and-egg scenario).

You can usually trust Spring to do the right thing. It detects configuration problems at container load time, such as references to nonexistent beans and loop dependencies. When the bean is actually created, Spring sets the properties and resolves the dependencies as late as possible. This means that if there is a problem with creating an object or one of its dependencies, the properly loaded Spring container will only generate an exception when the object is requested — for example, a bean will throw an exception due to missing or invalid properties. This may delay the visibility of some configuration issues, which is why ApplicationContext implements singleton-Scoped beans that are pre-instantiated by default. It takes some up-front time and memory to create the beans before they are actually needed, but problems with configuration metadata can be identified early, and you can override this default behavior so that singleton beans can be lazily initialized rather than eagerly pre-instantiated.

If there are no circular dependencies, when one or more collaboration beans are injected into a dependency bean, each collaboration bean is fully configured before being injected into the dependency bean. This means that if Bean A depends on Bean B, the Spring IoC container fully configures Bean B before calling setter methods on Bean A. In other words, the bean is instantiated, its dependencies are set, and the associated lifecycle methods are invoked.

Example of dependency injection

The following example is the use of XML-based configuration metadata setter dependency injection. A small section of the Spring XML configuration file specifies some bean definitions, as follows:

<bean id="exampleBean" class="examples.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"/>Copy the code

The following example shows the corresponding ExampleBean class:

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; }}Copy the code

In the previous example, the setter was declared to match the properties specified in the XML file. The following example uses constructor-based DI:

<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"/>Copy the code

The following example shows the corresponding ExampleBean class:

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; }}Copy the code

The constructor parameters specified in the bean definition are used as parameters to the constructor for ExampleBean.

Now consider a variation of this example, where instead of using the constructor, Spring is told to call a static factory method to return an instance of the 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"/>
Copy the code

The following example shows the corresponding ExampleBean class:

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; }}Copy the code

The arguments to the static factory method are supplied by the element, as if the constructor were actually used. The type of the class returned by the factory method need not be the same as the type of the class containing the static factory method (although it is the same in this case). Instance (non-static) factory methods can be used in essentially the same way (except using factory Bean properties instead of class properties), so we won’t discuss those details here.

1.4.2 Dependencies and Configuration Details

As described in the previous section, bean properties and constructor parameters can be defined as references or values to other collaborators. Spring’s XML-based configuration metadata provides and elements to support this.

Direct values (integers, strings, etc.)

The value attribute of the element specifies the attribute or constructor parameter as a human-readable string representation. Spring’s conversion service is used to convert these values from String to the actual type of an attribute or parameter. The following example shows the various values being set:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <! -- results in a setDriverClassName(String) call --> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="misterkaoli"/> </bean>Copy the code

The following example uses p-namespace for a more concise XML configuration:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/mydb"
        p:username="root"
        p:password="misterkaoli"/>

</beans>
Copy the code

You can also configure the values as java.util.properties, as shown below:

<bean id="mappings" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> <! -- typed as a java.util.Properties --> <property name="properties"> <value> jdbc.driver.className=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb </value> </property> </bean>Copy the code

Using JavaBeans’ PropertyEditor mechanism, the Spring container transforms the text in the element into an instance of java.util.properties. This is a nice shortcut, and one of the few places where the Spring team likes to use nested elements instead of the value attribute style.

Idref elements

The IDref element is simply a way to pass the ID of another bean in the container to the or element. The following example shows how to use it:

<bean id="theTargetBean" class="..." /> <bean id="theClientBean" class="..." > <property name="targetName"> <idref bean="theTargetBean"/> </property> </bean>Copy the code

The previous bean definition fragment (at run time) is exactly the same as the following fragment:

<bean id="theTargetBean" class="..." /> <bean id="client" class="..." > <property name="targetName" value="theTargetBean"/> </bean>Copy the code

The first form is preferable to the second because using the IDREF tag lets the container verify at deployment time that the referenced named bean actually exists. In the second variant, no validation is performed on the value of the targetName attribute passed to the client bean. This is only discovered when the client bean is actually instantiated (such as a typo). If the client bean is not instantiated when the container is created, this typo and the resulting exception may not be discovered until long after the container is deployed.

References to other beans

The ref element is or defines the last element in the element. Here, you set the value of the specified property of one bean to a reference to another container-managed bean. The referenced bean is a dependency of the bean whose properties are to be set, and it is initialized as needed before the properties are set. (If the collaborator is a singleton bean, it may have been initialized by the container.) All references are ultimately references to another object.

<ref bean="someBean"/>
Copy the code

The inner class

The element within the or element defines an inner bean, as follows:

<bean id="outer" class="..." > <! -- instead of using a reference to a target bean, simply define the target bean inline --> <property name="target"> <bean class="com.example.Person"> <! -- this is the inner bean --> <property name="name" value="Fiona Apple"/> <property name="age" value="25"/> </bean> </property> </bean>Copy the code

Internal bean definitions do not require an ID or name to be defined. If this value is specified, the container will not use it as an identifier. The container also ignores the scope flag when it is created, because the inner bean is always anonymous and is always created with the outer bean. It is not possible to access internal beans individually, nor is it possible to inject them into collaborative beans.

A collection of

The,,, and elements set the properties and parameters of the Java collection types List, set, Map, and Properties, respectively. The following example shows how to use them:

<bean id="moreComplexObject" class="example.ComplexObject"> <! -- results in a setAdminEmails(java.util.Properties) call --> <property name="adminEmails"> <props> <prop key="administrator">[email protected]</prop> <prop key="support">[email protected]</prop> <prop key="development">[email protected]</prop> </props> </property> <! -- results in a setSomeList(java.util.List) call --> <property name="someList"> <list> <value>a list element followed by  a reference</value> <ref bean="myDataSource" /> </list> </property> <! -- results in a setSomeMap(java.util.Map) call --> <property name="someMap"> <map> <entry key="an entry" value="just some string"/> <entry key ="a ref" value-ref="myDataSource"/> </map> </property> <! -- results in a setSomeSet(java.util.Set) call --> <property name="someSet"> <set> <value>just some string</value> <ref bean="myDataSource" /> </set> </property> </bean>Copy the code

The map key or value, the set value can also be any of the following elements:

bean | ref | idref | list | set | map | props | value | null
Copy the code

Collection of merger

The Spring container also supports merging collections. An application developer can define a parent element,, or and have the child element,, or inherit and override the values in the collection of parent elements. That is, the value of a subset is the result of merging the elements of the parent and the subset.

About the parent-child bean mechanism discussed in this section. For those unfamiliar with the definition of parent and child beans, read docs. Spring. IO /spring-fram…

The following example demonstrates collection merging:

<beans> <bean id="parent" abstract="true" class="example.ComplexObject"> <property name="adminEmails"> <props> <prop key="administrator">[email protected]</prop> <prop key="support">[email protected]</prop> </props> </property>  </bean> <bean id="child" parent="parent"> <property name="adminEmails"> <! -- the merge is specified on the child collection definition --> <props merge="true"> <prop key="sales">[email protected]</prop> <prop key="support">[email protected]</prop> </props> </property> </bean> <beans>Copy the code

Notice that the Merge =true attribute is used on the element of the adminEmails attribute defined by the child bean. When the container parses and instantiates the child bean, the resulting instance has a collection of adminEmails Properties that contains the result of merging the collection of adminEmails from the child bean with the collection of adminEmails from the parent bean. The elements contained are as follows:

[email protected]
[email protected]
[email protected]
Copy the code

The value set of the child attribute set inherits all the attribute elements of the parent attribute, and the support value of the child attribute overrides the value in the parent attribute set.

This merging behavior also applies to, and collection types. In the specific case of an element, the semantics associated with the list collection type (that is, the concept of an ordered collection of values) are maintained, with the values of the parent list before those of all child lists. There is no ordering for the Map, Set, and Properties collection types, so parent-child Map, Set, and Properties collection types used inside the container are unordered.

Limits on collection merging

You cannot combine different collection types (such as Map and List). If you try to do so, throw an appropriate Exception. The Merge attribute must be specified on the child definition. Specifying the merge attribute on the parent collection definition is redundant and does not result in the desired merge.

Strongly typed checksum collection

The introduction of generic types in Java 5 has led to the use of strongly typed collections. That is, you can declare a Collection type that contains only (for example)String elements. If you use Spring to inject strongly-typed Collection dependencies into beans, you can take advantage of Spring’s type-casting support to convert elements of strongly-typed Collection instances to the appropriate type before adding them to the Collection. The following Java class and bean definitions show how to do this:

public class SomeClass { private Map<String, Float> accounts; public void setAccounts(Map<String, Float> accounts) { this.accounts = accounts; }}Copy the code
<beans> <bean id="something" class=" x.y.someclass "> <property name="accounts"> <map> <entry key="one" value="9.99"/> < entry key = "two" value = "2.75" / > < entry key = "six" value = "3.99" / > < / map > < / property > < / bean > < / beans >Copy the code

When you are ready to inject the accounts property of something bean, generic information about the element type of strongly typed Map<String, Float> can be obtained by reflection. As a result, Spring’s type-conversion infrastructure identifies various value elements as Float and converts string values (9.99, 2.75, and 3.99) to actual Float types.

Null and Null values

Spring treats an empty string as an empty parameter. The following XML-based configuration metadata fragment sets the email attribute to a null value (“”).

<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>
Copy the code

The above example is equivalent to the following Java code:

exampleBean.setEmail("");
Copy the code

The element handles NULL values. The following listing shows an example:

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>
Copy the code

The above example is equivalent to the following Java code:

exampleBean.setEmail(null);
Copy the code

p-namespace

P-namespace allows you to describe collaboration bean dependencies using attributes of bean elements rather than elements.

Spring supports extensible configuration formats based on namespaces defined in XML Schema. The bean configuration format discussed in this chapter is defined in an XML Schema document. However, p-Namespace is not defined in the XSD file; it only exists in the Spring core.

The following example shows two XML fragments (the first using standard XML format and the second using p-namespace) that achieve the same result:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>

    <bean name="jane" class="com.example.Person">
        <property name="name" value="Jane Doe"/>
    </bean>
</beans>
Copy the code

This example not only contains property values using p-namespace, but also uses a special format to declare property references. The first bean definition is used to create a reference from bean John to bean Jane, and the second bean definition uses P :spouse-ref=” Jane “to do exactly the same job. In this case, spouse is the attribute name, and the -ref part indicates that this is not a direct value, but a reference to another bean.

P-namespace is not as flexible as the standard XML format. For example, the format of a declared attribute reference conflicts with an attribute ending in Ref, whereas the standard XML format does not. We recommend that you choose carefully, and communicate with your team members, to avoid generating XML documents that use more than one approach at a time.

c-namespace

Similar to the XML shortcut with p-Namespace, the c-Namespace introduced in Spring 3.1 is the equivalent of configuring constructor parameters. The following example uses C: Namespace to implement construction-based dependency injection:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/> <! -- traditional declaration with optional argument names --> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg name="thingTwo" ref="beanTwo"/> <constructor-arg name="thingThree" ref="beanThree"/> <constructor-arg name="email" value="[email protected]"/> </bean> <! -- c-namespace declaration with argument names --> <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo" c:thingThree-ref="beanThree" c:email="[email protected]"/> </beans>Copy the code

In rare cases where constructor parameter names are not available (usually when only bytecode is available), you can use the fallback parameter index, as follows:

<! -- c-namespace index declaration --> <bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree" c:_2="[email protected]"/>Copy the code

For XML syntax reasons, the index notation requires a leading _, because XML attribute names cannot start with a number (although some ides allow this).

In practice, the constructor resolution mechanism is very effective at matching parameters, so we recommend using name notation throughout the configuration unless we really need it.

The composite properties

Compound or nested property names can be used when setting bean properties, as long as all components of the path (except the final property name) are not empty. Consider the following bean definition:

<bean id="something" class="things.ThingOne">
    <property name="fred.bob.sammy" value="123" />
</bean>
Copy the code

The bean has a Fred variable, a Bob variable in the Fred variable, and a Sammy variable in the Bob variable, whose value is set to 123. For this to work, something’s Fred property and Fred’s Bob property cannot be empty after the bean is constructed. Otherwise, a NullPointerException is thrown.

1.4.3 use depends – on

If a bean is a dependency of another bean, this usually means that one bean is set as a property of the other bean. This is typically done using elements in XML-based configuration metadata. However, sometimes the dependencies between beans are not so straightforward. For example, when you need to trigger a static block of code in a class (such as database driver registration), Depends -on can explicitly force the initialization of one or more beans before the beans that use this element are initialized. The following example uses the Depends -on attribute to indicate a dependency on a single bean:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
Copy the code

To indicate a dependency on multiple beans, provide a list of beans as the value of the Depends -on attribute (commas, Spaces, and semicolons are all valid separators):

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Copy the code

The Depends -on attribute can specify a dependency at initialization or, in the case of a singleton bean, a corresponding destruction-time dependency. The dependent bean that defines the dependency to the given bean is destroyed first, and then the given bean itself. Therefore, this dependency also controls the destruction order.

1.4.4 lazy loading

By default, the ApplicationContext implementation creates and configits all singleton beans during initialization. In general, this pre-instantiation is desirable because errors in the configuration or surrounding environment are discovered immediately, rather than hours or even days later. When this behavior is undesirable, you can prevent pre-instantiation of singleton beans by marking the bean definition as lazy initialization. Lazy initialization beans tell the IoC container to create bean instances at the first request, not at startup.

In XML, this behavior is controlled by the lazy-init attribute on the element, as shown in the following example:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/> <bean name="not.lazy" class="com.something.AnotherBean"/>
Copy the code

When the above configuration is used by the ApplicationContext, lazy-init beans are not eagerly pre-instantiated when the ApplicationContext is started, and not. Lazy beans are eagerly pre-instantiated.

However, when a lazy-initialized bean is a dependency of a non-lazy-initialized singleton bean, the ApplicationContext creates the lazy-initialized bean at startup, and the lazy-initialized bean is instantiated and injected into the non-lazy-initialized singleton bean.

You can also control lazy initialization at the container level by using the default-lazy-init attribute on elements, as shown in the following example:

<beans default-lazy-init="true"> <! -- no beans will be pre-instantiated... --> </beans>Copy the code

1.4.5 Automatic assembly

The Spring container can automatically assemble relationships between collaborating beans. By examining the contents of the ApplicationContext, you can have Spring automatically resolve collaborators (other beans) for your bean. Automatic assembly has the following advantages:

  • Autowaging can significantly reduce the need to specify property or constructor parameters. (Other mechanisms discussed elsewhere in this chapter, such as bean templates, are also valuable in this regard.)
  • Autowiring can update the configuration as the object evolves. For example, if you need to add a dependency to a class, the dependency can be satisfied automatically without changing the configuration. Therefore, autowiring is especially useful during development.

When using XML-based configuration metadata (see dependency injection), you can use the element’s Autotowire attribute to specify the autowiring pattern for the bean definition. There are four modes of autowiring. You can dynamically specify the autowiring mode for each bean. The following table describes the four auto-assembly modes:

Mode Explanation
no Auto assembly is disabled (default). The Bean reference must be defined by the ‘ref’ element. For larger deployments, changing the default Settings is not recommended, as specifying collaborators explicitly provides greater control and clarity. In a way, it records the structure of the system.
byName Automatic assembly by property name. Spring looks for beans with the same name as the property that needs to be wired automatically. For example, if a bean definition is set to auto-assemble by name, and it contains a primary property (that is, it has a setMaster(..)) Method), Spring looks for a bean definition named Master and uses it to set the property.
byType If a bean of attribute type happens to exist in the container, let the attribute be wired automatically. If there are more than one, a fatal exception is thrown, indicating that you cannot use byType autowiring for the bean. If there is no matching bean, nothing happens (the property is not set).
constructor Similar to ‘byType, but applies to constructor arguments. If the container does not have a bean of constructor parameter type, a fatal error is raised.