El núcleo de la carga de componentes y la inicialización del contenedor IoC en Spring reside en la operación de actualización del contexto. Este proceso orquesta la creación, configuración y ensamblaje de todos los beans gestionados por la aplicación.
Orquestación del Ciclo de Vida: El Método de Actualización
La ejecución principal delega en la infraestructura de spring-context. A continuación, se presenta una representación estructural del flujo principal, donde se han adaptado las variables inetrnas y la organización del bloque para destacar las fases críticas del ciclo de vida sin alterar la lógica subyacente del framework:
@Override
public void refresh() throws BeansException, IllegalStateException {
this.lifecycleLock.lock();
try {
this.currentThread = Thread.currentThread();
StartupStep refreshStep = this.startupRecorder.start("spring.context.refresh");
setupRefreshState();
ConfigurableListableBeanFactory factory = acquireBeanFactory();
setupFactoryDefaults(factory);
try {
customizeBeanFactory(factory);
StartupStep bpStep = this.startupRecorder.start("spring.context.beans.post-process");
executeFactoryPostProcessors(factory);
attachBeanPostProcessors(factory);
bpStep.end();
setupMessageResolution();
setupEventBroadcasting();
executeCustomRefreshLogic();
attachApplicationListeners();
preInstantiateSingletons(factory);
broadcastRefreshCompletion();
} catch (RuntimeException | Error err) {
if (logger.isWarnEnabled()) {
logger.warn("Initialization failed, destroying beans: " + err);
}
cleanupSingletons();
rollbackRefresh(err);
throw err;
} finally {
refreshStep.end();
}
} finally {
this.currentThread = null;
this.lifecycleLock.unlock();
}
}
Fase 1: Preparación del Estado Inicial
Antes de manipular los beans, el contexto debe establecer sus marcas de tiempo, validar el entorno y preparar las colecciones de eventos y listeners tempranos.
protected void setupRefreshState() {
this.initTimestamp = System.currentTimeMillis();
this.isShutdown.set(false);
this.isActive.set(true);
logRefreshStart();
// Extensible para que las subclases carguen recursos específicos
loadCustomPropertySources();
// Verificación de propiedades obligatorias en el entorno
getEnvironment().verifyMandatoryProperties();
// Restauración o inicialización de los listeners de la aplicación
if (this.initialListeners == null) {
this.initialListeners = new LinkedHashSet<>(this.listeners);
} else {
this.listeners.clear();
this.listeners.addAll(this.initialListeners);
}
// Contenedor para eventos emitidos antes de que el multicaster esté listo
this.pendingEvents = new LinkedHashSet<>();
}
Fase 2: Obtención y Renovación del BeanFactory
El contenedor necesita una instancia fresca de BeanFactory. En implementaciones basadas en anotaciones como GenericApplicationContext, la factoría subyacente es DefaultListableBeanFactory. El proceso asegura que no se intente refrescar el contexto múltiples veces.
protected ConfigurableListableBeanFactory acquireBeanFactory() {
renewBeanFactory();
return retrieveBeanFactory();
}
La lógica de renovación en el contexto genérico previene ejecuciones concurrentes o duplicadas mediante operaciones atómicas:
@Override
protected final void renewBeanFactory() throws IllegalStateException {
if (!this.hasRefreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"Multiple refresh attempts are not allowed. Invoke 'refresh' only once.");
}
this.factory.setSerializationId(getId());
}
Fase 3: Configuración de la Factoría de Beans
Una vez obtenida la instancia de la factoría, se procede a inyectar dependencias estándar y configurar el entorno de ejecución. Esto encluye la definición del ClassLoader, el resolvedor de expresiones, y el registro de interfaces de conocimiento (como BeanFactoryAware o ApplicationContextAware) para que los componentes puedan interactuar con el contenedor durente su instanciación.