Dependency Injection (DI) is a core pattern where an object's dependencies are provided externally rather than the object creating them itself.
Constructor Injection involves providing dependencies through a class's constructor at the time of object creation. This ensures the object is fully initialized and immutable if dependencies are declared as final.
Setter Injection involves providing dependencies through setter methods after the object is instantiated. This offers more flexibility for optional dependencies and reconfiguration.
Demonstrating Setter Injection for Complex Types
First, define a simple supporting class representing a complex property.
public class Location {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Next, a primary class Pupil demonstrates injection for various property types.
import java.util.*;
public class Pupil {
private Location location;
private String[] textbooks;
private String pupilName;
private Set<String> sports;
private String guardian;
private List<String> interests;
private Properties settings;
private Map<String, String> credentials;
// Getters and Setters for all fields
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public String[] getTextbooks() {
return textbooks;
}
public void setTextbooks(String[] textbooks) {
this.textbooks = textbooks;
}
public String getPupilName() {
return pupilName;
}
public void setPupilName(String pupilName) {
this.pupilName = pupilName;
}
public Set<String> getSports() {
return sports;
}
public void setSports(Set<String> sports) {
this.sports = sports;
}
public String getGuardian() {
return guardian;
}
public void setGuardian(String guardian) {
this.guardian = guardian;
}
public List<String> getInterests() {
return interests;
}
public void setInterests(List<String> interests) {
this.interests = interests;
}
public Properties getSettings() {
return settings;
}
public void setSettings(Properties settings) {
this.settings = settings;
}
public Map<String, String> getCredentials() {
return credentials;
}
public void setCredentials(Map<String, String> credentials) {
this.credentials = credentials;
}
@Override
public String toString() {
return "Pupil{" +
"location=" + location +
", textbooks=" + Arrays.toString(textbooks) +
", pupilName='" + pupilName + '\'' +
", sports=" + sports +
", guardian='" + guardian + '\'' +
", interests=" + interests +
", settings=" + settings +
", credentials=" + credentials +
'}';
}
}
Define the bean configuration in an XML file application-context.xml, using <property> elements for setter injection.
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pupilBean" class="com.example.pojo.Pupil">
<!-- Primitive value injection -->
<property name="pupilName" value="Alex" />
<!-- Bean reference injection -->
<property name="location" ref="locationBean" />
<!-- Array injection -->
<property name="textbooks">
<array>
<value>Mathematics</value>
<value>Science</value>
</array>
</property>
<!-- List injection -->
<property name="interests">
<list>
<value>Reading</value>
<value>Music</value>
</list>
</property>
<!-- Map injection -->
<property name="credentials">
<map>
<entry key="Student ID" value="12345" />
<entry key="Library Card" value="L789" />
</map>
</property>
<!-- Set injection -->
<property name="sports">
<set>
<value>Soccer</value>
<value>Swimming</value>
</set>
</property>
<!-- Null value injection -->
<property name="guardian">
<null />
</property>
<!-- Properties injection -->
<property name="settings">
<props>
<prop key="Grade">10</prop>
<prop key="Section">A</prop>
</props>
</property>
</bean>
<bean id="locationBean" class="com.example.pojo.Location" />
</beans>
A test class can be used to verify the configuration.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InjectionTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
Pupil pupilInstance = (Pupil) ctx.getBean("pupilBean");
System.out.println(pupilInstance.toString());
}
}
XML Configuration Shortcuts
Spring provides namespace shortcuts to simplify XML configuration.
The p-namespace (xmlns:p="http://www.springframework.org/schema/p") allows for more concise property injection.
<bean id="pupilBean2" class="com.example.pojo.Pupil"
p:pupilName="Jordan" p:guardian="Parent Name" />
The c-namespace (xmlns:c="http://www.springframework.org/schema/c") provides a shorthand for constructor arguments.
<bean id="pupilBean3" class="com.example.pojo.Pupil"
c:pupilName="Casey" c:guardian="Guardian Name" />