Understanding Spring IoC Container: Principles, XML Configuration, Custom Factories, and Bean Scopes
This article explains the operation of the Spring IoC container, the DIP principle, dependency injection, XML bean definitions, custom and static factories, FactoryBean usage, bean scopes (singleton and prototype), and demonstrates their behavior with Java code examples.
The Spring IoC container (BeanFactory or ApplicationContext) acts as a super‑factory that creates, manages, and controls the lifecycle of beans, applying the Dependency Inversion Principle (DIP) to shift control from application code to the container and achieve module decoupling.
Dependency Injection (DI) is the core mechanism that implements IoC, allowing beans to receive their required collaborators automatically.
Bean definitions are typically expressed in XML. For example:
<bean id="userService" class="org.nf.service.impl.UserServiceImpl"></bean>Attributes:
id : unique identifier for retrieving the bean.
class : fully‑qualified class name; Spring instantiates the class via reflection and registers the instance.
A custom factory can be declared as a bean and used to create other beans:
public class PeopleServiceFactory {
public UserService create() {
// The created object will also be managed by the container
return new PeopleServiceImpl();
}
} <bean id="peopleServiceFactory" class="org.nf.factory.PeopleServiceFactory"/>
<bean id="peopleService" factory-bean="peopleServiceFactory" factory-method="create"/>Static factories work similarly but use a static method:
public class StudentServiceFactory {
public static UserService create() {
return new StudentServiceImpl();
}
} <bean id="studentService" class="org.nf.factory.StudentServiceFactory" factory-method="create"/>For more control, implement Spring's FactoryBean interface:
public class TeacherServiceFactoryBean implements FactoryBean
{
@Override
public UserService getObject() throws Exception {
return new TeacherServiceImpl();
}
@Override
public Class
getObjectType() {
return TeacherServiceImpl.class;
}
@Override
public boolean isSingleton() {
return true;
}
} <bean id="teacherService" class="org.nf.factory.TeacherServiceFactoryBean"/>Bean scope is defined with the scope attribute. singleton (default) means a single shared instance; prototype creates a new instance on each request.
<bean id="userService" class="org.nf.service.impl.UserServiceImpl" scope="prototype"/>Internally, Spring stores singleton beans in a Map<String, Object> where the key is the bean id and the value is the instantiated object, while prototype beans are kept in a Map<String, Class<?>> that holds the class reference for on‑demand instantiation.
Map
singleton = new HashMap<>();
Object object = clazz.getConstructor().newInstance();
singleton.put("userService", object); Map
> prototypeMap = new HashMap<>();
prototypeMap.put("userService", clazz);
Class
beanClass = prototypeMap.get("userService");
beanClass.getConstructor().newInstance();A test class demonstrates the difference:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService s1 = context.getBean(UserService.class);
UserService s2 = context.getBean(UserService.class);
System.out.println(s1);
System.out.println(s2);When the bean is singleton, the printed references are identical; when prototype, they differ, confirming separate instances.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.