Spring: diferencia entre BeanFactory y ApplicationContext

Spring es uno de los marcos Java EE más populares. Es un marco liviano de código abierto que permite a los desarrolladores de Java EE crear aplicaciones empresariales simples, confiables y escalables. Proporciona programación orientada a aspectos. Brinda soporte para todos los servicios genéricos y de middleware y se enfoca principalmente en proporcionar varias formas de ayudarlo a administrar sus objetos comerciales. Es un marco modularizado donde todos los módulos están diseñados sobre el concepto llamado «Inyección de dependencia».

Inyección de dependencia: La inyección de dependencia es un patrón de diseño que permite que el contenedor de resorte ‘inyecte’ objetos en otros objetos o dependencias. En palabras simples, los contenedores Spring se encargan del control de la creación de objetos y la gestión de los componentes Spring.

Contenedores de primavera

Spring Framework proporciona dos de los paquetes más fundamentales e importantes, son los paquetes org.springframework.beans y org.springframework.context . El código en estos paquetes proporciona la base para las funciones de inversión de control/inyección de dependencia de Spring . Los contenedores de primavera son responsables de crear objetos de frijol e inyectarlos en las clases. Los dos contenedores son a saber,

  1. BeanFactory(I) : disponible en el paquete org.springframework.beans.factory.
  2. ApplicationContext(I) : disponible en el paquete rg.springframework.context.

La interfaz BeanFactory

Esta es la interfaz raíz para acceder a un contenedor Spring bean. Es el contenedor real que instancia, configura y administra varios beans. Estos beans colaboran entre sí y, por lo tanto, tienen dependencias entre ellos. Estas dependencias se reflejan en los datos de configuración utilizados por BeanFactory. Esta interfaz está implementada por los objetos que contienen una serie de definiciones de beans, cada una de ellas identificada de forma única por un nombre de string. La clase de implementación más común utilizada para este BeanFactory es XmlBeanFactory disponible en el paquete org.springframework.beans.factory.xml. 

Nota: BeanFactory está obsoleto desde Spring 3.0.

Código de ejemplo:

Java

ClassPathResource resource = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(resource);

La interfaz de contexto de aplicación

Esta interfaz está diseñada sobre la interfaz BeanFactory. La interfaz ApplicationContext es el contenedor avanzado que mejora la funcionalidad de BeanFactory en un estilo más orientado al marco. Mientras que BeanFactory proporciona una funcionalidad básica para administrar y manipular beans, a menudo de forma programática, ApplicationContext proporciona una funcionalidad adicional como MessageSource, acceso a recursos, propagación de eventos a beans, carga de contextos múltiples (jerárquicos), etc. Hay tantas clases de implementación que se pueden usar como ClassPathXmlApplicationContext , FileSystemXmlApplicationContext , AnnotationConfigWebApplicationContext , etc.

Código de ejemplo:

Java

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Jerarquía de interfaz

A continuación se muestra la jerarquía de BeanFactory(I) y ApplicationContext(I) con algunas de sus clases de implementación.

Hierarchy Structure

Estructura jerárquica

Tabla de diferencias

BeanFactory

ApplicationContext

Es un contenedor fundamental que proporciona la funcionalidad básica para administrar beans. Es un contenedor avanzado que amplía BeanFactory que proporciona toda la funcionalidad básica y agrega algunas funciones avanzadas.
Es adecuado para construir aplicaciones independientes. Es adecuado para construir aplicaciones Web, integración con módulos AOP, ORM y aplicaciones distribuidas.
Solo admite ámbitos de bean Singleton y Prototype. Admite todos los tipos de ámbitos de bean, como Singleton, Prototype, Request, Session, etc.
No admite anotaciones. En Bean Autowiring, necesitamos configurar las propiedades solo en el archivo XML. Es compatible con la configuración basada en anotaciones en Bean Autowiring.
Esta interfaz no proporciona funcionalidad de mensajería (i18n o internacionalización). La interfaz ApplicationContext amplía la interfaz MessageSource, por lo que proporciona funcionalidad de mensajería (i18n o internacionalización).
BeanFactory no admite la función de publicación de eventos. El manejo de eventos en ApplicationContext se proporciona a través de la clase ApplicationEvent y la interfaz ApplicationListener.
En BeanFactory, necesitamos registrar manualmente BeanPostProcessors y BeanFactoryPostProcessors. ApplicationContext registra automáticamente BeanFactoryPostProcessor y BeanPostProcessor al inicio.
BeanFactory creará un objeto bean cuando se llame al método getBean(), lo que lo convierte en una inicialización diferida. ApplicationContext carga todos los beans y crea objetos solo en el momento del inicio, lo que lo convierte en una inicialización ansiosa.
La interfaz de BeanFactory proporciona funciones básicas solo por lo que requiere menos memoria. Para aplicaciones independientes donde las características básicas son suficientes y cuando el consumo de memoria es crítico, podemos usar BeanFactory. ApplicationContext proporciona todas las funciones básicas y funciones avanzadas, incluidas varias que están orientadas a aplicaciones empresariales, por lo que requieren más memoria.

Explicación de Funcionalidades

1) Auto cableado de frijoles

El contenedor Spring es capaz de conectar automáticamente las relaciones entre los beans colaboradores. Significa que es posible permitir que Spring resuelva automáticamente otros beans para su bean al inspeccionar el contenido del Contenedor. El cableado automático se especifica por bean y, por lo tanto, se puede habilitar para algunos beans, mientras que otros beans no se conectarán automáticamente. Usando el cableado automático, es posible reducir o eliminar la necesidad de especificar propiedades o argumentos de construcción.

Cableado automático en BeanFactory:

En BeanFactory, el modo de conexión automática para una definición de bean se especifica utilizando el atributo ‘ autoconexión’ del elemento <bean/> en un archivo de configuración basado en XML.

Ejemplo:

XML

<bean id="welcomeBean" class="com.geeks.beans.WelcomeBean" autowire="byName"/>

Cableado automático en ApplicationContext:

En ApplicationContext, podemos usar la anotación «@Autowired» encima de las propiedades o los métodos de establecimiento en la clase de bean.

Ejemplo:

Java

@Autowired
private String name;

2) Registro de BeanPostProcessors y BeanFactoryPostProcessors

BeanPostProcessors: un posprocesador Bean es una clase Java que implementa la interfaz org.springframework.beans.factory.config.BeanPostProcessor, que consta de dos métodos de devolución de llamada. Permite la modificación personalizada de nuevas instancias de bean creadas por contenedores de primavera. Si queremos implementar alguna lógica personalizada antes o después de que el contenedor Spring termine de crear instancias, configurar e inicializar un bean, podemos conectar una o más implementaciones de BeanPostProcessor. 

BeanFactoryPostProcessors: un posprocesador de Bean Factory es una clase Java que implementa la interfaz org.springframework.beans.factory.config.BeanFactoryPostProcessor. Funciona en las definiciones de bean o en los metadatos de configuración del bean antes de que se creen realmente los beans. Estos se invocan para resolver dependencias de tiempo de ejecución.

Registrarse en BeanFactory:

Al usar la interfaz BeanFactory, si hay beans que implementan las interfaces BeanPostProcessor o BeanFactoryPostProcessor, los posprocesadores de beans deben registrarse explícitamente de forma manual.

Ejemplo:

Java

// create BeanFactory
ConfigurableBeanFactory factory = new ConfigurableBeanFactory(resource);
 
// register needed BeanPostProcessors
HelloBeanPostProcessor bpp = new HelloBeanPostProcessor();
factory.addBeanPostProcessor(bpp);

Registro en ApplicationContext:

Una interfaz ApplicationContext detectará automáticamente si hay beans implementados en ella implementando las interfaces BeanPostProcessor o BeanFactoryPostProcessor y los registrará como posprocesadores, y luego la fábrica los llamará apropiadamente en la creación del bean. Por lo tanto, es mucho más conveniente usar postprocesadores de fábrica de beans en ApplicationContexts que en BeanFactories simples.

3) Cargando/Inicializando los beans

Veremos un ejemplo sencillo para entender la diferencia entre los contenedores BeanFactory y ApplicationContext.

Ejemplo de BeanFactory:

Cree las siguientes clases y archivos XML.

WelcomeBean.java: Una clase de bean de Java para definir las propiedades, métodos getter/setter de las propiedades.

Java

public class WelcomeBean {
 
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String welcomeMsg() {
        return "Welcome " + name;
    }
 
    public void initializeBean() {
        System.out.println("Welcome Bean is initialized!!");
    }
 
    public void destroyBean() {
        System.out.println("Welcome Bean is destroyed!!");
    }
 
}

beans.xml: archivo XML para configurar los beans.

XML

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="welcomeBean" class="WelcomeBean"
        init-method="initializeBean" destroy-method="destroyBean">
        <property name="name" value="geek" />
    </bean>
 
</beans>

WelcomeBeanTest.java: Clase principal para crear el objeto BeanFactory y ejecutar la aplicación.

Java

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
 
import com.geeks.beans.WelcomeBean;
 
public class WelcomeBeanTest {
    public static void main(String[] args) {
 
        ClassPathResource res = new ClassPathResource("beans.xml");
        XmlBeanFactory factory = new XmlBeanFactory(res);
        System.out.println("Before getBean() method");
 
        WelcomeBean welcome = (WelcomeBean) factory.getBean("welcomeBean");
        System.out.println(welcome.welcomeMsg());
        ((XmlBeanFactory)factory).destroySingletons();
 
    }
 
}

Ejecución:

  • En este ejemplo, llamamos al método welcomeMsg() para imprimir el mensaje en la consola.
  • En la clase de bean, especificamos los métodos, initializeBean() como método de inicio y destroyBean() como método de destrucción. Esta configuración se especifica en el archivo beans.xml .
  • Cuando ejecutamos la aplicación, se ejecutará el método principal. En eso, primero, creará el objeto de recurso para cargar el archivo XML, luego se crea el objeto XmlBeanFactory.
  • Y luego la aplicación imprime, antes del método getBean() en la consola. Ahora, se llama al método getBean(), en este punto, el contenedor cargará el bean e inicializará la clase de bean. Hasta que la ejecución llegue al método getBean(), el contenedor BeanFactory no inicializará el bean. Por lo tanto, se llama inicialización perezosa.
  • Entonces, la salida será la siguiente,
Output

Producción

Ejemplo de contexto de aplicación:

Ahora, crearemos la misma aplicación usando ApplicationContext.

HelloBean.java: una clase de bean de Java para definir las propiedades, métodos getter/setter de las propiedades.

Java

public class HelloBean {
 
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String helloMsg() {
        return "Hello " + name;
    }
 
    public void initializeBean() {
        System.out.println("Hello Bean is initialized!!");
    }
 
    public void destroyBean() {
        System.out.println("Hello Bean is destroyed!!");
    }
 
}

applicationContext.xml: archivo XML para configurar los beans.

Java

public class WelcomeBean {
 
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String welcomeMsg() {
        return "Welcome " + name;
    }
 
    public void initializeBean() {
        System.out.println("Welcome Bean is initialized!!");
    }
 
    public void destroyBean() {
        System.out.println("Welcome Bean is destroyed!!");
    }
 
}

HelloBeanTest.java : clase principal para crear el objeto ApplicationContext y ejecutar la aplicación.

Java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import com.geeks.beans.HelloBean;
 
public class HelloBeanTest {
 
    public static void main(String[] args) {
 
        ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("Before getBean() method");
        HelloBean hello = (HelloBean) con.getBean("helloBean");
 
        System.out.println(hello.helloMsg());
        ((ClassPathXmlApplicationContext) con).close();
 
    }
 
}

Ejecución:

  • En este ejemplo, llamamos al método helloMsg() para imprimir el mensaje en la consola.
  • En la clase de bean, especificamos los métodos, initializeBean() como método de inicio y destroyBean() como método de destrucción. Esta configuración se especifica en el archivo applicationContext.xml .
  • Cuando ejecutamos la aplicación, se ejecutará el método principal. Primero, será el objeto ApplicationContext y ahora el contenedor identificará todos los objetos bean y se inicializará antes de llamar al método getBean(). Por lo tanto, se llama inicialización ansiosa .
  • Imprime el mensaje de inicialización antes de llamar al método getBean().
  • Entonces, la salida será la siguiente,
Output

Producción

Si compara ambas salidas, podemos ver que al usar BeanFactory, los beans se inicializarán cuando se llame al método getBean(), lo que significa bajo demanda. Pero ApplicationContext inicializará todos los beans solo al inicio.

4) Funcionalidad de internacionalización en ApplicationContext

La interfaz ApplicationContext amplía las interfaces denominadas MessageSource y NestingMessageSource y, por lo tanto, proporciona funcionalidad de mensajería (i18n) o internacionalización. Es capaz de resolver mensajes jerárquicos.

Ejemplo:

Java

String getMessage (String code, Object[] args, String default, Locale loc)

Este es el método básico utilizado para recuperar un mensaje de MessageSource. Cuando no se encuentra ningún mensaje para la configuración regional especificada, se utiliza el mensaje predeterminado. Cuando se carga ApplicationContext, busca automáticamente un bean MessageSource definido en el contexto. El bean debe tener el nombre messageSource . Actualmente, Spring proporciona dos implementaciones de MessageSource. Son ResourceBundleMessageSource y StaticMessageSource .

5) Propagación de eventos en ApplicationContext

ApplicationContext proporciona manejo de eventos a través de la clase ApplicationEvent y la interfaz ApplicationListener . Si un bean implementa la interfaz ApplicationListener y se implementa en el contexto, cada vez que se publica un ApplicationEvent en ApplicationContext, ese bean será notificado. Este es el patrón de diseño  estándar de Observer .

Spring proporciona tres eventos estándar, a saber, ContextRefreshedEvent, ContextClosedEvent y RequestHandledEvent. También podemos crear eventos personalizados llamando al métodopublishEvent() en ApplicationContext y especificando un parámetro que es una instancia de nuestra clase de evento personalizado que implementa ApplicationEvent. 

Conclusión

Como discutimos anteriormente, los contenedores ApplicationContext y BeanFactory se utilizan para crear y administrar los objetos de bean. BeanFactory es la interfaz fundamental que proporciona toda la funcionalidad básica para crear y gestionar los objetos bean y la interfaz ApplicationContext amplía la interfaz BeanFactory, proporciona toda la funcionalidad básica y también algunas características avanzadas como la capacidad de cargar recursos de archivos de forma genérica, para publicar eventos a oyentes registrados, para resolver mensajes, apoyar la internacionalización, etc.

Publicación traducida automáticamente

Artículo escrito por yaminitalisetty y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *