The foundation of Spring's bean management system revolves around several key components that work together to define, instantiate, and manage beans. Below is a simplified implemantation illustrating these core concepts.
BeanDefinition: Metadata Container for Beans
BeanDefinition acts as a metadata holder for a bean, storing information such as its class type and scope (e.g., singleton or prototype). The following example captures the essential structure:
package org.springframework.spring.beans.factory.config;
public class BeanDefinition {
private Class> beanClass;
public BeanDefinition(Class<?> beanClass) {
this.beanClass = beanClass;
}
public Class<?> getBeanClass() {
return beanClass;
}
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
}
DefaultListableBeanFactory: Primary Bean Registry
This class serves as the central registry for bean definitions, using a Map to store bean names and their corresponding definitions:
package org.springframework.spring.beans.factory.support;
import org.springframework.spring.beans.BeansException;
import org.springframework.spring.beans.factory.config.BeanDefinition;
import java.util.HashMap;
import java.util.Map;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String name, BeanDefinition definition) {
beanDefinitionMap.put(name, definition);
}
@Override
public BeanDefinition getBeanDefinition(String name) throws BeansException {
BeanDefinition definition = beanDefinitionMap.get(name);
if (definition == null) {
throw new BeansException("No bean named '" + name + "' is defined");
}
return definition;
}
}
Singleton Registry and Bean Instantiation Flow
When requesting a bean via getBean(), the container first checks if an instance already exists in the singleton cache. If not, it creates a new instance based on the registered BeanDefinition.
The singleton instances are managed by DefaultSingletonBeanRegistry:
package org.springframework.spring.beans.factory.support;
import org.springframework.spring.beans.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new HashMap<>();
@Override
public Object getSingleton(String name) {
return singletonObjects.get(name);
}
public void addSingleton(String name, Object bean) {
singletonObjects.put(name, bean);
}
}
AbstractBeanFactory coordinates the retreival logic:
package org.springframework.spring.beans.factory.support;
import org.springframework.spring.beans.BeansException;
import org.springframework.spring.beans.factory.BeanFactory;
import org.springframework.spring.beans.factory.config.BeanDefinition;
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry
implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
Object existingBean = getSingleton(name);
if (existingBean != null) {
return existingBean;
}
BeanDefinition definition = getBeanDefinition(name);
Object createdBean = createBean(name, definition);
return createdBean;
}
protected abstract BeanDefinition getBeanDefinition(String name) throws BeansException;
protected abstract Object createBean(String name, BeanDefinition definition) throws BeansException;
}
Finally, AbstractAutowireCapableBeanFactory provieds a basic implementation for bean creation:
package org.springframework.spring.beans.factory.support;
import org.springframework.spring.beans.BeansException;
import org.springframework.spring.beans.factory.config.BeanDefinition;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String name, BeanDefinition definition) throws BeansException {
Class<?> clazz = definition.getBeanClass();
Object instance;
try {
instance = clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new BeansException("Failed to instantiate bean: " + name, e);
}
addSingleton(name, instance);
return instance;
}
}