Spring Core – XML – Dependency Injection

Dependency Injection Approaches

Spring Core is the base of all other Spring modules. The main thing that we need to understand in Spring core is – dependency injection.

  1. Field injection
  2. Setter injection
  3. Constructor injection

We should always use ‘Code to interfaces’.

Setter Injection

Setter injection is a type of dependency injection used in the Spring Framework where dependencies are injected into a bean using setter methods. This approach involves calling setter methods on the bean to set its dependencies after the bean is instantiated.

Example :

First, define a Java class for your bean. This class should have setter methods for the dependencies you want to inject.

public class MyBean {
private Dependency dependency;

// Setter method for the dependency
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
}

Define the class for the dependency that will be injected into your bean.

public class Dependency {
// Dependency class definition
}

In your Spring XML configuration file (e.g., applicationContext.xml), define the bean configurations including setter injection.

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

<!-- Define the bean for the dependency -->
<bean id="dependencyBean" class="com.example.Dependency"/>

<!-- Define the bean for MyBean with setter injection -->
<bean id="myBean" class="com.example.MyBean">
<property name="dependency" ref="dependencyBean"/>
</bean>
</beans>

In the above XML configuration:

  • <bean> elements are used to define beans.
  • <property> elements are used within the bean definition to specify property values.
  • name attribute of <property> element corresponds to the name of the setter method in the bean class (setDependency in this case).
  • ref attribute specifies the reference of the dependency bean (dependencyBean in this case).

Injecting values

Setter injection can be used for injecting primitive types and strings into a bean.

In Spring Framework XML configuration, the <property> element is used to set property values of a bean. The name attribute of the <property> element specifies the name of the property (i.e., the name of the setter method) to be invoked on the bean, and the value attribute specifies the value to be assigned to that property.

In the XML configuration, you can directly specify the value using the value attribute of the <property> element.

<bean id="myBean" class="com.example.MyBean">
<property name="propertyName" value="propertyValue"/>
</bean>

In the above XML configuration:

  • myBean is the id of the bean being defined.
  • com.example.MyBean is the fully qualified class name of the bean.
  • <property> element sets the value of a property on the bean.
  • name="propertyName" specifies the name of the property (i.e., the name of the setter method) to be invoked on the bean (setPropertyName in this case).
  • value="propertyValue" specifies the value to be assigned to that property.

For example, if MyBean class has a setter method setPropertyName, Spring will call this method and pass "propertyValue" as an argument to set the property value when instantiating MyBean.

Injecting another object

In Spring Framework, setter injection using the ref attribute is a way to inject another bean as a dependency by referencing it using its id.

Example application

POJO Classes

DeliveryService.java -- interface
package com.rndayala.java;
public interface DeliveryService
{
boolean courierService(double amount);
}

// Implementation classes
BlueDart.java
package com.rndayala.java;
public class BlueDart implements DeliveryService {
@Override
public boolean courierService(double amount) {
System.out.println("Delivery Service using BlueDart courier service : " + amount);
return true;
}
}

FedEx.java
package com.rndayala.java;
public class FedEx implements DeliveryService {
@Override
public boolean courierService(double amount) {
System.out.println("Delivery Service using FedEx courier service : " + amount);
return true;
}
}

Amazon.java
package com.rndayala.java;
// Loose coupling example
// target class
public class Amazon {
// FedEx, BlueDart, FirstFlight -- these are all dependent objects
private DeliveryService service;

public void setService(DeliveryService service) {
this.service = service;
}

public boolean initiateDelivery(double amount) {
return service.courierService(amount);
}
}

Bean configuration – applicationcontext.xml

<bean id="bluedart" class="com.rndayala.springcore.beans.BlueDart">
<!-- Configurations and dependencies go here -->
</bean>
<bean id="firstflight" class="com.rndayala.springcore.beans.FirstFlight"/>
<bean id="fedex" class="com.rndayala.springcore.beans.FedEx"/>
<bean id="amzon" class="com.rndayala.springcore.beans.Amazon">
<!-- injecting objects -->
<property ref="fedex" name="service"></property>
</bean>

NOTE —

In the Amazon class, we can have : 
a. Instance variable as : private DeliveryService abcd;
b. Setter method parameter as : public void setXyz(DeliveryService pqrt)
c. bean property reference name as : <property ref=”fedex” name=”xyz” />

Ideally what is happening here is, based on the property reference name we give, Spring framework is internally creating one setter method, like setXyz. As long as this setter method is available, the setter injection is happening.

Main application – LanchApp.java

How do we access the beans ?

package com.rndayala.springcore.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.rndayala.springcore.beans.Amazon;

public class LaunchApp {
public static void main(String[] args) {
// activating Spring IoC container
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext.xml");

Amazon amz = context.getBean("amazon", Amazon.class);
boolean b = amz.initiateDelivery(1045.0);
}
}

The ClassPathXmlApplicationContext manages the lifecycle of the beans, handling their instantiation, dependency injection, and destruction according to the configuration in the XML file.

ClassPathXmlApplicationContext is a specific implementation of the Spring ApplicationContext interface that loads the context definition from an XML file located in the classpath. This class is part of the Spring Framework and is commonly used in Spring applications for configuring and managing beans.

You define your bean configurations in an XML file. This file usually contains information about the beans to be managed by the Spring container, including their class names, dependencies, and other settings.

In your Java code, you instantiate ClassPathXmlApplicationContext, specifying the XML configuration file’s location in the classpath.
Once the context is created, you can retrieve beans from it using their IDs or names. In the example above, context.getBean("amzon", Amazon.class) retrieves a bean named “amzon” of type Amazon from the context.

Additional example – Setter injection

<!-- Configure AnotherBean -->
<bean id="anotherBean" class="com.example.AnotherBean">
<property name="message" value="Hello, Setter Injection with Ref!"/>
</bean>

<!-- Configure MyBean with setter injection using ref -->
<bean id="myBean" class="com.example.MyBean">
<property name="anotherBean" ref="anotherBean"/>
</bean>
  • The first <bean> element configures the AnotherBean with an ID of “anotherBean” and sets its “message” property.
  • The second <bean> element configures the MyBean class with an ID of “myBean” and performs setter injection for the anotherBean property using the ref attribute.

The ref attribute is used to specify the ID of another bean, and Spring injects the corresponding bean instance into the property, specified by name attribute (for setter injection) or constructor (for constructor injection) of the current bean.

NOTE – Setter injection allows you to specify optional dependencies by providing default values or allowing null values. If a dependency is not required, simply omit the corresponding <property> element from the XML configuration.


Constructor Injection

Constructor injection in the Spring Framework involves injecting dependencies into a bean through its constructor. It’s an alternative to setter injection and offers some advantages, such as ensuring that all required dependencies are provided when the bean is instantiated and promoting immutability.

Example :

First, define a Java class for your bean. This class should have a constructor that accepts dependencies as parameters.

public class MyBean {
private Dependency dependency;

// Constructor injection
public MyBean(Dependency dependency) {
this.dependency = dependency;
}

// Other methods
}

Define the class for the dependency that will be injected into your bean.

public class Dependency {
// Dependency class definition
}

In your Spring XML configuration file (e.g., applicationContext.xml), define the bean configurations including constructor injection.

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

<!-- Define the bean for the dependency -->
<bean id="dependencyBean" class="com.example.Dependency"/>

<!-- Define the bean for MyBean with constructor injection -->
<bean id="myBean" class="com.example.MyBean">
<constructor-arg ref="dependencyBean"/>
</bean>
</beans>

In the above XML configuration:

  • <bean> elements are used to define beans.
  • <constructor-arg> elements are used within the bean definition to specify constructor arguments.
  • ref attribute specifies the reference of the dependency bean (dependencyBean in this case).

Constructor injection is particularly useful when a bean has mandatory dependencies that must be provided at the time of instantiation. It also promotes immutability by allowing dependencies to be set only once during object creation.

DeliveryService.java -- interface
package com.rndayala.java;
public interface DeliveryService
{
boolean courierService(double amount);
}

// Implementation classes
BlueDart.java
package com.rndayala.java;
public class BlueDart implements DeliveryService {
@Override
public boolean courierService(double amount) {
System.out.println("Delivery Service using BlueDart courier service : " + amount);
return true;
}
}

FedEx.java
package com.rndayala.java;
public class FedEx implements DeliveryService {
@Override
public boolean courierService(double amount) {
System.out.println("Delivery Service using FedEx courier service : " + amount);
return true;
}
}

Amazon.java
package com.rndayala.java;
// Loose coupling example
// target class
public class Amazon {
// FedEx, BlueDart, FirstFlight -- these are all dependent objects
private DeliveryService service;

public void Amazon(DeliveryService service) {
this.service = service;
}

public void setService(DeliveryService service) {
this.service = service;
}

public boolean initiateDelivery(double amount) {
return service.courierService(amount);
}
}

Bean configuration – applicationcontext.xml

<bean id="bluedart" class="com.rndayala.springcore.beans.BlueDart">
<!-- Configurations and dependencies go here -->
</bean>
<bean id="firstflight" class="com.rndayala.springcore.beans.FirstFlight"/>
<bean id="fedex" class="com.rndayala.springcore.beans.FedEx"/>
<bean id="amzon" class="com.rndayala.springcore.beans.Amazon">
<!-- injecting objects -->
<constructor-arg ref="bluedart" name="service"></constructor-arg>
<property ref="fedex" name="service"></property>
</bean>

If we have both constructor and setter injection for the same property, after constructor injection is done, then setter injection overrides.


Additional Notes – order of parameter injection

We can create multiple beans for the same class, injecting different parameters for the bean.

Creating a new project. Create one bean class – Employee.

By default, Constructor parameters injection happens in the order the parameters are present in the constructor. However, if you want to specify parameters in different order, you need to use an index attribute or name attribute.

Getting the bean using class name 


Cyclic injection

Cyclic injection between classes

This can be achieved : 

  1. Using setter injection
  2. Using one setter, one constructor injection

Can’t be achieved where both objects depend on constructor injection.

Setter injection happens after the object is created.


Dependency injection – using “autowire” attribute

Is it possible to perform dependency injection without using setter or constructor injection ?

Yes, it is possible, by the mechanism of autowiring.

In the context of the Spring Framework in Java, the autowire attribute is used within the <bean> element in the Spring XML configuration file. This attribute specifies the autowiring mode for the Spring bean.

Autowiring is a feature of Spring IoC (Inversion of Control) container that automatically injects the dependencies of a bean.

autowire attribute

The autowire attribute can take several values, each representing a different autowiring mode. Here are some common values for the autowire attribute:

  • no: This is the default value. It means no autowiring, and you have to explicitly specify the dependencies using <property> or <constructor-arg> elements.
<bean id="exampleBean" class="com.example.ExampleBean" autowire="no">
<!-- Other bean configuration →
</bean>
  • byName: Autowiring by property name. Spring will try to match and inject a bean by looking at the property name in the current bean and trying to find a bean with a matching name in the container.
<bean id="exampleBean" class="com.example.ExampleBean" autowire="byName">
<!-- Other bean configuration →
</bean>
  • byType: Autowiring by data type. Spring will try to match and inject a bean by looking at the property type in the current bean and trying to find a bean of the same type in the container.
<bean id="exampleBean" class="com.example.ExampleBean" autowire="byType">
<!-- Other bean configuration →
</bean>
  • constructor: Autowiring by constructor. Spring will try to match and inject dependencies by looking at the constructor parameters of the current bean.
<bean id="exampleBean" class="com.example.ExampleBean" autowire="constructor">
<!-- Other bean configuration →
</bean>

These are just a few examples, and the choice of autowiring mode depends on the specific requirements of your application. The autowire attribute simplifies the configuration process by reducing the need for explicit dependency declarations. Instead, Spring automatically resolves and injects the dependencies based on the specified autowiring mode.

In case you have bean definitions like these : 

You have a DeliveryService interface which is being implemented by multiple classes, FedEx, BlueDart, FirstFlight and you have a class Amazon which has an attribute of type DeliveryService that can be matched to any of the implementation classes.

<!-- bean definitions here -->
<bean id="bluedart" class="com.rndayala.beans.BlueDart" />
<bean id="firstflight" class="com.rndayala.beans.FirstFlight" />
<bean id="fedex" class="com.rndayala.beans.FedEx" />

<bean id="amazon" class="com.rndayala.beans.Amazon" autowire="byType" />

For your project, when you try to autowire byType, and if multiple objects are found for injection, then it will throw an error.

Dec 28, 2023 8:00:39 AM org.springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'amazon' defined in class path resource [applicationcontext.xml]: Unsatisfied dependency expressed through bean property 'service'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.rndayala.beans.DeliveryService' available: expected single matching bean but found 3: bluedart,firstflight,fedexException in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'amazon' defined in class path resource [applicationcontext.xml]: Unsatisfied dependency expressed through bean property 'service'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.rndayala.beans.DeliveryService' available: expected single matching bean but found 3: bluedart,firstflight,fedex

If we comment on the other two beans, then Spring can resolve the dependency and inject (either setter or constructor injection).

<!-- bean definitions here -->
<!-- <bean id="bluedart" class="com.rndayala.beans.BlueDart" />
<bean id="firstflight" class="com.rndayala.beans.FirstFlight" /> -->
<bean id="fedex" class="com.rndayala.beans.FedEx" />

<bean id="amazon" class="com.rndayala.beans.Amazon" autowire="byType" />

If you want Spring IoC container to inject one of the many dependent objects, then we can use attribute primary.

<!-- bean definitions here -->
<bean id="bluedart" class="com.rndayala.beans.BlueDart" primary="true" />
<bean id="firstflight" class="com.rndayala.beans.FirstFlight" />
<bean id="fedex" class="com.rndayala.beans.FedEx" />

<bean id="amazon" class="com.rndayala.beans.Amazon" autowire="byType" />

Injecting using byName :

<!-- bean definitions here -->
<bean id="bluedart" class="com.rndayala.beans.BlueDart" primary="true" />
<bean id="service" class="com.rndayala.beans.FirstFlight" />
<bean id="fedex" class="com.rndayala.beans.FedEx" />

<bean id="amazon" class="com.rndayala.beans.Amazon" autowire="byName" />

autowire-candidate property

In the Spring Framework, the autowire-candidate property is used to indicate whether a particular bean should be considered as a candidate for autowiring by the container. This property is mainly relevant when you have multiple beans of the same type, and Spring needs to determine which one to inject.

When Spring performs autowiring, it tries to match and inject dependencies based on their types. If there are multiple beans of the same type and Spring cannot determine which one to choose, it may throw an exception. The autowire-candidate property allows you to explicitly specify whether a bean should be considered as a candidate for autowiring.


Spring Core – XML Injection : p-namespace, c-namespace

In Spring XML, p-namespace is the XML shortcut for <property> tag to inject bean dependency. The p-namespace replaces <property> tag in XML configuration. Because of Spring p-namespace, the length of xml code will be reduced and it increases the readability of XML configuration.

To use Spring p-namespace, It needs to be declared with xmlns:p somewhere within the XML element or a parent element of which they are being used.

To enable the p-namespace feature, we need to add the xmlns:p=”http://www.springframework.org/schema/p” and refer to p-namespace using p to inject any dependency.

In Spring XML, c-namespace is an XML shortcut for the <constructor-arg> tag, which is used to inject bean dependency via the constructor. In XML configuration, the c-namespace replaces the <constructor-arg> tag. Spring c-namespace reduces the length of xml code and improves the readability of XML configuration.

To enable the c-namespace feature, we must add the xmlns:c=”http://www.springframework.org/schema/c” and use c to inject any dependency.

The “p” namespace allows you to set properties of a bean (setter injection) using a shorthand syntax. It stands for “property” and is particularly useful for reducing XML verbosity.

<bean id="exampleBean" class="com.example.Example">
<property name="name" value="John" />
<property name="age" value="25" />
</bean>

changes to :

<bean id="exampleBean" class="com.example.Example" p:name="John" p:age="25" />

The “c” namespace is used for constructor arguments. It stands for “constructor-arg.”

<bean id="exampleBean" class="com.example.Example" c:name="John" c:age="25" />

Example :