Understanding how Spring "wires" its "beans".
In Spring, dependencies can be injected by the following popular means:
- XML-based container config
-
the Java bean is loaded into the spring container registry via a configuration XML that "describes" the POJO attributes.
- Annotation-based container config
-
the Java bean is loaded into the spring container registry via stereotype hints annotated on the POJO with values in an external XML file.
- Java-based container configuration
-
Configuration is completely moved to Java, no need for XML at all.
Let us walk through a few examples.
The previous chapter detailed how Spring loads XML to manage bean configurations. It included a basic example of Spring using the default constructor to instantiate a bean.
-
For the model, we have two model objects to look at
⇒ ColoredShape.java
⇒ ColoredShapeHolder.java -
A plain Java example with no spring used
⇒ Ex00_NoFrameworkExample.java. -
Several instances of
ColoredShapeHolder
are created in this example.
Running the main method should output > 1 count of colored shape: [ green circle ] > 5 count of colored shape: [ red rectangle ] > 7 count of colored shape: [ cyan cylinder ] > 3 count of colored shape: [ black box ] created with default values on ColoredShape which itself is instantiated with a default constructor.
We will take a look at how a dependency injection can be configured using an XML file.
This example demonstrates a loading of a bean with a default constructor call. No custom values are set. The XML configuration simply instantiates a bean to be made available to the holder.
-
The Java code to execute
⇒ Ex01_DIThroughConstructorSimple.java.
This class has aClassPathXmlApplicationContext
which reads the XML configuration. TheApplicationContext
is the Spring Inversion of Control. Themain
method transfers control of loading beans to theClassPathXmlApplicationContext
, which then loads beans from the XML file. The XML file provides an injection of aColoredShape
bean into aColoredShapeHolder
bean via Constructor Injection based on determining the types of arguments. -
The Java code for the model loaded from the XML file
⇒ ColoredShape.java.
⇒ ColoredShapeHolder.java. -
Here is the XML configuration for this Spring class
⇒ ex01-di-through-constructor-simple.xml. -
Notice how the two argument constructor from
ColoredShapeHolder
is used to inject theColoredShape
based on argument types. The order, in this case, does not matter, since the types accepted by the constructor are unique.
Running the main method should output > 1 count of colored shape: [ green circle ] created with quantity of 1 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with a constructor call passing arguments. The arguments represent the parameter names. The XML configuration simply instantiates a bean to be made available to the holder and sets constructor values based on the names.
-
The Java code to execute
⇒ Ex02_DIThroughConstructorNamed.java
This class has aClassPathXmlApplicationContext
which reads the XML configuration. TheApplicationContext
is the Spring Inversion of Control. Themain
method transfers control of loading beans to theClassPathXmlApplicationContext
, which then loads beans from the XML file. The XML file provides an injection of aColoredShape
bean into aColoredShapeHolder
bean via Constructor Injection using constructor argument names. -
Here is the XML configuration for this Spring class
⇒ ex02-di-through-constructor-named.xml. -
Notice how the two argument constructor from
ColoredShapeHolder
is used to inject theColoredShape
based on argument names. The order, in this case, does not matter, since the argument names are unique.
Running the main method should output > 5 count of colored shape: [ red rectangle ] created with quantity of 5 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with a constructor call passing arguments. The arguments represent the parameter indices. The XML configuration simply instantiates a bean to be made available to the holder.
-
The Java code to execute
⇒ Ex03_DIThroughConstructorIndex.java
This class has aClassPathXmlApplicationContext
which reads the XML configuration. TheApplicationContext
is the Spring Inversion of Control. Themain
method transfers control of loading beans to theClassPathXmlApplicationContext
, which then loads beans from the XML file. The XML file provides an injection of aColoredShape
bean into aColoredShapeHolder
bean via Constructor Injection using constructor argument indices. -
Here is the XML configuration for this Spring class
⇒ ex03-di-through-constructor-index.xml. -
Notice how the two argument constructor from
ColoredShapeHolder
is used to inject theColoredShape
based on argument indices. The order, in this case, does not matter, since the argument indices are well-defined.
Running the main method should output > 7 count of colored shape: [ cyan cylinder ] created with quantity of 7 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with setter calls passing values. The property includes a named attribute of each bean property. The XML configuration simply instantiates a bean to be made available to the holder.
-
The Java code to execute
⇒ Ex04_DIThroughSetters.java
This class has aClassPathXmlApplicationContext
which reads the XML configuration. TheApplicationContext
is the Spring Inversion of Control. Themain
method transfers control of loading beans to theClassPathXmlApplicationContext
, which then loads beans from the XML file. The XML file provides an injection of aColoredShape
bean into aColoredShapeHolder
bean via Setter Injection using setters. -
Here is the XML configuration for this Spring class
⇒ ex04-di-through-setters.xml. -
Notice how the bean is declared with property values being set in both
ColoredShape
which is then is used to inject the property inColoredShapeHolder
based on property setters. The order of setting properties, does not matter, since the properties can be set in any order.
Running the main method should output > 3 count of colored shape: [ black box ] created with quantity of 3 configured for the bean ColoredShapeHolder.
The next few examples demonstrate how Java annotations can be used to inject dependencies.
This example demonstrates a loading of a bean with setter annotations to wire. The property includes a named attribute of each bean property. The XML configuration simply instantiates a bean to be made available to the holder. The ColoredShape is NOT passed to the ColoredShapeHolder.
-
The Java code to execute
⇒ Ex05_DIThroughAnnotationSetters.java
This class loads beans via an XML and then invokes aSetterAnnotatedColoredShapeHolder
. -
Here is the XML configuration for this Spring class
⇒ ex05-di-through-annotation-setters.xml
The XML only declares two beans, but does nothing to inject. Also notice a special instruction to thebeans
schema, and the addition of a<context:annotation-config/>
excerpt. The addition of the schemas and the declaration of this excerpt are important to process annotations. -
The Java Code that injects the dependency
⇒ SetterAnnotatedColoredShapeHolder.java
This class has an@Autowired
annotation for thesetColoredShape()
. The XML file defines the beans that are loaded via theClassPathXmlApplicationContext
. This part creates a registry of beans. TheSetterAnnotatedColoredShapeHolder
has the@Autowired
annotation on the setter, which queries the registry to find a matching bean to set theColoredShape
.
Running the main method should output > 11 count of colored shape: [ red rhombus ] created with quantity of 11 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with constructor annotations to wire. The property includes a named attribute of each bean property. The XML configuration simply instantiates a bean to be made available to the holder. The ColoredShape is NOT passed to the ColoredShapeHolder.
-
The Java code to execute
⇒ Ex06_DIThroughAnnotationConstructor.java
This class loads beans via an XML and then invokes aConstructorAnnotatedColoredShapeHolder
. -
Here is the XML configuration for this Spring class
⇒ ex06-di-through-annotation-constructor.xml
The XML only declares two beans, but does nothing to inject. Also notice a special instruction to thebeans
schema, and the addition of a<context:annotation-config/>
excerpt. The addition of the schemas and the declaration of this excerpt are important to process annotations. -
The Java Code that injects the dependency
⇒ ConstructorAnnotatedColoredShapeHolder.java
This class has an@Autowired
annotation for the constructor. The XML file defines the beans that are loaded via theClassPathXmlApplicationContext
. This part creates a registry of beans. TheConstructorAnnotatedColoredShapeHolder
has the@Autowired
annotation on the constructor, which queries the registry to find a matching bean to set theColoredShape
.
Running the main method should output > 2 count of colored shape: [ orange oval ] created with quantity of 2 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with constructor annotations to wire. The property includes a named attribute of each bean property. The XML configuration simply instantiates a bean to be made available to the holder and includes a qualifier. The ColoredShape is NOT passed to the ColoredShapeHolder.
-
The Java code to execute
⇒ Ex07_DIThroughAnnotationWithQualifiers.java
This class loads beans via an XML and then invokes aConstructorAnnotatedQualifiedColoredShapeHolder
. -
Here is the XML configuration for this Spring class
⇒ ex07-di-through-annotation-with-qualifiers.xml
The XML only declares three beans, but does nothing to inject. There are twoColoredShape
beans, which will lead to a confusion about which bean to load. Notice the new qualifier definition for bothColoredShape
beans. Also notice a special instruction to thebeans
schema, and the addition of a<context:annotation-config/>
excerpt. The addition of the schemas and the declaration of this excerpt are important to process annotations. -
The Java Code that injects the dependency
⇒ ConstructorAnnotatedQualifiedColoredShapeHolder.java
This class has an@Autowired
annotation for the constructor. The Constructor parameter also has an annotation of aQualifier
which specifies that the bean to load uses thethePinkPolygon
bean, and not the aColoredShape. The XML file defines the beans that are loaded via theClassPathXmlApplicationContext
. This part creates a registry of beans. TheConstructorAnnotatedColoredShapeHolder
has the@Autowired
annotation on the constructor, which queries the registry to find a matching bean to set theColoredShape
.
Running the main method should output > 4 count of colored shape: [ pink polygon ] created with quantity of 4 configured for the bean ColoredShapeHolder.
The next few examples demonstrate how Java annotations, without any XML, can be used to inject dependencies.
This example demonstrates a loading of a bean with wiring via component scans. The annotation on the main class allows scanning of all classes in the base package specified in the parameter. Special annotations that define the behaviour of a class. Spring framework treats such annotated classes as first class beans. Any classes marked with a stereotype indicates that the class being a bean are picked into the context.
-
The Java code to execute
⇒ Ex08_DIThroughJava.java
This class has an annotation to@ComponentScan
all Spring-annotated classes in thebnymellon.training.spring.framework.model
package. This is the Java equivalent of creating bean definitions in XML. Notice how the @ComponentScan points to a base package to scan, Spring picks up all classes marked as a@Component
from the base package. Notice the use of anAnnotationConfigApplicationContext
to load the context beans via annotations. Since we do not pass any classes, package or configuration location, the annotation context need to be first registered and then refreshed to ensure scanning and subsequent loading of all necessary Spring-related beans. -
A few model classes are created that contain the
@Component
annotation informing Spring to load them up as beans. ⇒ BlackBox.java. ⇒ OrangeOval.java.
Notice there are otherColoredShape
classes that are NOT loaded into the Spring context, since they are not marked with the@Component
annotation. Examples includeCyanCylinder
andRedRectangle
. -
The Java code that autowires
⇒ AutowiredColoredShapeHolder.java
This class autowires the constructor to look for an instance ofOrangeOval
in the context. The AutowiredColoredShapeHolder itself picks up the OrangeOval loaded during the component scan. Since only one instance is declared, it is found and auto-wired in.
Running the main method should output > 1 count of colored shape: [ orange oval ] created with quantity of 2 configured for the bean ColoredShapeHolder.
This example demonstrates a loading of a bean with wiring configured in a Java object. The annotation on the main class allows scanning of all classes in the base package specified in the parameter. Any class marked with @Configuration annotation (this annotation is also called a stereotype), indicate that it replaces XML configurations previously discussed.
-
The Java code to execute
⇒ Ex09_DIThroughJavaConfiguration.java
This class uses the sameAnnotationConfigApplicationContext
as used in the previous example. Since the configuration points to a specific Java class, it can skip the need to register and refresh. TheColoredShapeHolder
instance is retrieved by name from the context. -
The Java code that provides the configurations
⇒ DIConfiguration.java
This class provides the beans (with their names) of tealtrapezoid, tealTrapezoidHolder and redRectangleHolder to be loaded into the Spring context.
Running the main method should output > 10 count of colored shape: [ teal trapezoid ]
The lab exercise is to fix the broken tests. Follow the instructions to fix the TODOs to get the JUnit test to pass.
Prev | TOC | Next |
---|---|---|