This article continues with the previous article, describing dependency processing in the spring Ioc.
Depend on
In general, enterprise applications will not have only one object (or spring Bean). Even the simplest applications need multiple objects to work together to make the end user see a complete Application. The next section will explain how developers can start by simply defining separate beans, to let these beans work together in one Application.
Dependency Injection
Dependency Injection is a process that allows an object to define their dependencies only by constructing parameters, parameters of factory methods, or configured Properties. These dependencies are also objects that the object needs to work Together. The container injects these dependencies when the bean is Created. The process completely reverses the instantiation or reference dependency of the Bean itself, so this process is also called inversion of control .
When the criteria for dependency injection are used, it is easier to manage dependencies between decoupled objects and make the code simpler. Objects no longer care about dependencies, and do not need to know the location of the dependent Classes. In this case, the Developer's class is easier to test, especially if the developer relies on interfaces or abstract classes, and developers can easily mock objects in unit Tests.
Dependency injection is mainly used in two ways, one is based on the injection of the constructor, and the other is based on the setter method of dependency Injection.
constructor-based Dependency Injection
constructor-based Dependency Injection is the constructor of the class that is called by the IOC container, and the parameters of the constructor represent the objects that the bean depends on. is basically the same as calling a static factory method with Parameters. The following example shows a class that implements dependency injection through a constructor Function. It is important to note that this class has no special place, just a simple, generic class that does not depend on any particular interface, base class, or annotation of any container.
publicclass SimpleMovieLister { // the SimpleMovieLister has a dependency on a MovieFinder private MovieFinder movieFinder; // a constructor so that the Spring container can inject a MovieFinder publicSimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // business logic that actually uses the injected MovieFinder is omitted...}
Parameter resolution of constructors
Parameter resolution of a constructor is matched by the type of the Parameter. If there is no ambiguity in the Bean's constructor arguments, then the order of the constructor arguments is the instantiation of these parameters and the order in which they are loaded. Refer to the following code:
package x.y;public class Foo { public Foo(Bar bar, Baz baz) { ... }}
Assuming Bar
and Baz
not related at the inheritance level, there is no ambiguity, the following configuration can work properly, the developer does not need to go to the <constructor-arg>
element to specify the parameters of the constructor parameter index or type Information.
<beans> <bean id="foo" class="x.y.foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> </Bean> <bean id="bar" class="x.y.bar"/> <bean id="baz" class="x.y.baz"/></Beans>
When referencing another bean, the match works fine if the type is OK (as in the example above). when using a simple type, for example, the <value>true</value>
Spring IOC container cannot determine the type of value, so it cannot be matched. Consider the following code:
package examples;publicclass ExampleBean { // Number of years to calculate the Ultimate Answer privateint years; // The Answer to Life, the Universe, and Everything private String ultimateAnswer; publicExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }}
In this case, the container can type
implement a simple type match by using the properties of the constructor parameter. Like what:
<bean id="exampleBean"class="examples.ExampleBean"> type="int"value="7500000"/> type="java.lang.String"value="42"/></bean>
Or use index
properties to specify the location of the construction parameters, such as:
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/></bean>
This index is also intended to solve the problem that there are multiple parameters of the same type in the constructor that cannot be precisely matched. It is important to note that the index is based on the 0 start.
Developers can also remove ambiguity by the name of the Parameter.
<bean id = "examplebean" class =" examples. Examplebean "; <constructor-arg name = "years" value = "7500000" /> < constructor-arg name = "ultimateanswer" value = "a" /> </bean ;
It is important to note that the code for this work must have debug markup compilation enabled so that spring can find the parameter names from Constructors. Developers can also use @ConstructorProperties
annotations to explicitly declare the name of a constructor, such as the following code:
package examples;publicclass ExampleBean { // Fields omitted @ConstructorProperties({"years""ultimateAnswer"}) publicExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }}
Dependency Injection based on setter mode
A dependency injection based on a setter function is a container that invokes a Bean's parameterless constructor, or a factory method without parameters, and then calls the setter method to implement the dependency Injection.
The following example shows a dependency injection using the setter method, the following class object is simply a Pojo object, independent of any spring special interface, base class, or Annotation.
public Class Simplemovielister {//the Simplemovielister have a dependency on the Moviefinde R 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 This actually uses the injected Moviefinder is omitted ... }
ApplicationContext
Managed beans are supported for constructor-based dependency injection or setter-based dependency Injection. It also supports the use of setter methods to inject dependency again after the dependency is injected through the Constructor. Developers BeanDefinition
can use PropertyEditor
instances to freely choose the way they are injected. however, most developers do not use these classes directly, but rather with bean
definitions that prefer xml, or annotations-based components (such as use @Component
, @Controller
etc.) or methods that are used on the configured @Configuration
classes @Bean
.
is it based on a constructor or setter method?
Because developers can mix both, it is usually better to inject the necessary dependencies through the constructor to inject some optional dependencies through the Setter. The annotations above the setter method @Required
can be used to construct the necessary dependencies.
The spring team recommends a constructor-based injection, because this approach encourages developers to develop components into immutable objects and ensures that the injection dependency is not null
. also, the constructor-based injected component is fully constructed when it is called by the Client. of course, on the other hand, too many of the constructor parameters are very bad code, which means that the class seems to have too many functions, and it is best to refactor different functions Apart.
setter-based injection is only for optional dependencies, but it is also best to configure some reasonable default Values. otherwise, A non-null check is required on the dependencies of the Code. One of the conveniences of setter-based injection is that this approach can be re-configured and Re-injected.
Two styles of dependency injection are suitable for most situations, but sometimes when using a third-party library, the developer may not have the source code, and the Third-party codes do not have setter methods, then only the constructor-based dependency injection is Used.
Dependency parsing process
The container parses the bean as Follows:
- Created and instantiated according to the metadata of the description
ApplicationContext
. Configuration metadata can be through xml, Java code, or Annotations.
- The dependency of each bean is represented by a constructor parameter or a property or parameter of a static factory Method. These dependencies are injected and loaded when the bean is Created.
- Each property or constructor parameter is either an actual defined value or a reference to another bean in the Container.
- Each property or construct parameter can be converted according to its specified type. Spring can also turn a string into the default Java intrinsic type, such as,,
int
long
String
, boolean
etc.
The spring container is validated against each bean at the time the container is Created. however, the Bean's properties are not configured when the bean is not actually created. A singleton type of Bean is configured as a pre-instance state when the container is Created. The Bean is Scope
introduced in a FOLLOW-UP. Other beans are created only at the time of the Request. Obviously creating a bean object will have a dependency graph. This diagram represents a dependency between beans, which the container determines the order in which the beans are created and configured.
Cyclic Dependency
If the developer primarily uses a constructor-based dependency injection, there is a good chance that a loop-dependent scenario will Occur.
For example, Class A relies on an instance of Class B in a constructor, whereas a constructor of Class B relies on an instance of Class A. If you do this by configuring Class A and Class B to inject each other, the Spring IOC container will find this runtime's cyclic dependency and throw it BeanCurrentlyInCreationException
.
Developers can use setter methods to configure dependency injection, which solves this Problem. or, instead of using constructor-based dependency injection, use only dependency injection based on the setter Method. In other words, Although not recommended, developers can configure cyclic dependencies as dependency injection based on setter METHODS.
Developers can trust spring to handle beans correctly. Spring can discover configuration problems during loading, such as referencing to nonexistent beans or cyclic dependencies. Spring will load attributes or parse dependencies as late as the Bean is Created. This also means that the spring container is loaded correctly and throws an exception when the bean injection dependency error Occurs. For example, The bean throws a missing attribute or the property is Illegal. The parsing of this delay is also why ApplicationContext
the implementation causes the singleton bean to be in the Pre-instantiation State. This way, by ApplicationContext
creating, You can consume some memory costs before actually using the bean to discover the configuration Problem. Developers can also override the default behavior to delay loading a singleton bean instead of being in a pre-instantiated State.
If there is no circular dependency, the dependency that the bean refers to will take precedence over the fully constructed Dependency. For example, if Bean a relies on bean b, the spring IOC container configures Bean B First and then invokes the setter method of bean A to construct Bean A. In other words, The bean is instantiated first, then injected into the dependency, and then the invocation of the associated life cycle Method.
example of dependency injection
The following example uses metadata based on XML configuration and then uses setter mode for dependency Injection. The code is 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 "/>
public classExamplebean {PrivateAnotherbean beanone;PrivateYetanotherbean beantwo;Private intI public void Setbeanone(anotherbean beanone) { this. Beanone = beanone; } public void Setbeantwo(yetanotherbean Beantwo) { this. Beantwo = beantwo; } public void Setintegerproperty(intI) { this. i = i; }}
In the above example, the setter method declaration is consistent with the XML file, and the following example is a constructor-based 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 "/>
publicclass ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; privateint i; publicExampleBean( int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; }}
The constructor parameter in the bean definition is the dependency that is used to construct ExampleBean
.
The following example returns a Bean instance through a static factory Method.
<beanID="examplebean" class="examples. Examplebean "Factory-method="createinstance"> <constructor-argref="anotherexamplebean"/> <constructor-argref="yetanotherbean"/> <constructor-arg value="1"/></bean><beanID="anotherexamplebean" class="examples. Anotherbean "/><beanID="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; }}
The parameters of the factory method are also specified by the <constructor-arg/>
label, and the dependency injection based on the constructor is Consistent. As mentioned before, the returned type does not need to be consistent with the exampleBean
class
attributes in, and the class
class that contains the factory method is Specified. of course, The above example is Consistent. The factory-bean
instance factory method used to construct the bean is not much described here.
Spring Core technology (ii) dependency and injection of--spring