JavaRush /Blog Java /Random-ES /Marco de primavera. Introducción
Marchello
Nivel 20
Санкт-Петербург

Marco de primavera. Introducción

Publicado en el grupo Random-ES
¡Hola! Mientras la administración de JavaRush trabaja en nuevos niveles, quiero comenzar una serie de artículos de capacitación sobre Spring Framework. Sí, sé que ya hay mucho material sobre este tema en Internet, pero, como muestra la práctica, todos están al nivel de Hola Mundo. No quiero hablar de cómo colocar correctamente las anotaciones, sino de cómo funciona todo "bajo el capó". El artículo está dirigido a quienes ya han trabajado con este marco de una forma u otra y están familiarizados con los conceptos básicos. Marco de primavera.  Introducción - 1

Inicializando el contexto.

Así que comencemos con lo básico. En mi opinión, uno de los puntos más importantes es comprender cómo se configura el contexto y cómo se inicializan los beans. Como sabes, antes de que Spring comience a funcionar, es necesario configurarlo. En tiempos antediluvianos, esto se hacía usando archivos xml (en algunos proyectos, principalmente los antiguos, continúan haciéndolo hasta el día de hoy). A continuación se muestra un pequeño ejemplo de dicho archivo de configuración:
<?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-3.0.xsd">

   <bean id="helloWorld" class="ru.javarush.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>
En general, esto es suficiente para crear un par de controladores y ejecutar una startup (que no despegará). Pero, ¿cómo hará que esta configuración funcione Spring? Y aquí es donde las cosas se ponen interesantes. Para que Spring comprenda nuestra configuración, existe un archivo XmlBeanDefinitionReader. BeanDefinitionEste es un componente interno de Spring que escanea (analiza) xml y crea archivos basados ​​en lo que escribimos allí . BeanDefinitiones un objeto que almacena información sobre el bean. Esto incluye: desde qué clase se debe crear (el bean); alcance; si está instalada la inicialización diferida; ¿Es necesario inicializar antes de este bean otro y otras propiedades que se describen en xml? Todos los recibidos BeanDefinitionse agregan a HashMap, en el que el identificador es el nombre del bean (establecido por usted o asignado por Spring) y BeanDefinitionel objeto en sí. BeanDefinitionUna vez creado todo , aparece un nuevo héroe en el escenario: BeanFactory. Este objeto itera sobre HashMap’es BeanDefinition, crea beans basados ​​en ellos y los coloca en un contenedor de IoC. Hay un matiz aquí, de hecho, cuando se inicia la aplicación, el contenedor de IoC contendrá beans que tienen un alcance Singleton (configurado de forma predeterminada), mientras que el resto se crean cuando son necesarios (prototipo, solicitud, sesión). Y ahora una pequeña digresión, conozcamos a otro personaje.

Conozca BeanPostProcessor. (PPB)

postprocesador de frijolesEl hecho es que un bean no es necesariamente una clase de lógica empresarial para su aplicación. Un bean también se denomina bean de infraestructura. En resumen, un bean de infraestructura es una clase que configura sus beans lógicos de negocios (sí, demasiados beans). Te contaré más sobre esto a continuación, pero para que quede un poco más claro qué configura exactamente BPP, te daré un ejemplo. ¿ Están todos familiarizados con el resumen @Autowired? Por lo tanto, usted AutowiredAnnotationBeanPostProcessores responsable de garantizar que todas sus clases estén integradas entre sí. desconocido

Volvamos a BeanFactory

Conociendo ahora acerca de BPP, es necesario aclarar que al iterar sobre HashMaplos, BeanDefinitiontodos primero se crean y se colocan por separado (no en el contenedor de IoC) BeanPostProcessor. Después de esto, se crean beans regulares de nuestra lógica de negocios, se colocan en un contenedor de IoC y su configuración comienza utilizando BPP diferidos por separado. Y así sucede, cada BPP tiene 2 métodos:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Itera a través de nuestros contenedores dos veces. La primera vez que se llama al método postProcessorBeforeInitializationy la segunda vez que se llama al método postProcessorAfterInitialization. Seguramente te ha surgido la duda de por qué se necesitan dos métodos, déjame explicarte. El hecho es que para procesar algunas anotaciones (como @Transactional, por ejemplo), nuestro bean se reemplaza por una clase proxy. Para entender por qué se hace esto, es necesario saber cómo funciona @Transactional, y así es como funciona. Debe agregar un par de líneas más de código al método marcado con esta anotación sobre la marcha. ¿Cómo hacerlo? Así es, creando una clase de proxy, dentro de la cual se agregará el código necesario al método requerido. Ahora imagina esta situación, tenemos una clase:
class A {
    @Autowired
    private SomeClass someClass;

    @Transactional
    public void method() {
        // модификатор доступа обязательно public
    }
}
Esta clase tiene 2 anotaciones @Autowiredy @Transactional. Ambas anotaciones son procesadas por BPP diferentes. Si funciona primero AutowiredBPP, entonces todo estará bien, pero si no, nos encontraremos con este problema. El hecho es que cuando se crea la clase de proxy, toda la metainformación se pierde. En otras palabras, no habrá información sobre la anotación @Autowireden la clase proxy y, por lo tanto AutowiredBPP, no funcionará, lo que significa que nuestro campo someClasstendrá el valor null, lo que probablemente conducirá a una NPE. También vale la pena saber que entre llamadas a métodos, postProcessorBeforeInitializationse postProcessorAfterInitializationllama al método - init, si lo hay. Este es básicamente el segundo constructor, pero la diferencia es que en este momento todas nuestras dependencias ya están integradas en la clase y podemos acceder a ellas desde initel método -. Entonces, una vez más el algoritmo de inicialización del contexto:
  1. XmlBeanDefinitionReaderescanea nuestro archivo de configuración xml.
  2. Crea BeanDefinitiony los pone HashMap.
  3. Viene BeanFactoryy de esto HashMappor separado suma todos los BeanPostProcessor's.
  4. Crea BeanDefinitionbeans a partir de 's y los coloca en un contenedor de IoC.
  5. Aquí los BPP vienen y configuran estos beans usando 2 métodos.
  6. Listo.
En realidad, eso es todo, escribe si te gustó el artículo y si vale la pena seguir escribiendo este tipo de tutoriales.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION