¡Te saludo, Habr!
Este artículo será útil para aquellos que ya comenzaron a aprender Java e incluso lograron alcanzar cierto éxito en la comprensión de Java Core, y ahora escuché la palabra Spring. Y, tal vez, ni siquiera una vez: el conocimiento del Spring Framework, al menos, aparece en las descripciones de muchas vacantes para javists. Este artículo lo ayudará a subir el primer paso: comprender la idea general de un marco tan popular.
Comencemos desde lejos. Existe una inversión de control, en ruso - Inversión de control, en forma abreviada - IoC. IoC es uno de los principios que acerca nuestro código a la soltura. IoC es la delegación de parte de nuestras responsabilidades a un componente externo.
Existen diferentes implementaciones del enfoque de IoC, estamos interesados en una de ellas: la inyección de dependencia, la inyección de dependencia. ¿Qué es esto? El nombre habla por sí mismo, así que intentaré revelarlo usando un ejemplo. Estamos escribiendo una aplicación que automatiza el funcionamiento de una cadena de tiendas. Hay clases de Tienda (tienda) y Vendedor (vendedor). La clase Vendedor tiene un campo de tipo Tienda: la tienda en la que trabaja el vendedor. Entonces nos enfrentamos a la adicción: el vendedor depende de la tienda. Ahora pensemos en cómo el objeto Shop entra en el objeto Vendedor. Hay opciones:
- Impleméntelo a través del diseñador e inmediatamente, al crear el vendedor, especifique la tienda en la que trabaja:
public class Seller { private Shop shop; public Seller(Shop shop) { this.shop = shop; } }
- Cree un setter y, usando su llamada, configure la tienda para el vendedor:
public class Seller { private Shop shop; public void setShop(Shop shop) { this.shop = shop; } }
Los dos métodos enumerados son la implementación de la inyección de dependencia. Y finalmente, llegamos a la primavera: proporciona otra forma de inyectar dependencias.
En términos generales, Spring es una gama muy amplia de bibliotecas para muchas ocasiones. Hay Spring MVC para crear rápidamente aplicaciones web, Spring Security para implementar la autorización en la aplicación y Spring Data para trabajar con bases de datos y mucho más. Pero Spring IoC está solo: este es el tipo básico de resorte que implementa el tema que estamos estudiando: la inyección de dependencia. Spring IoC merece atención al comienzo del estudio de las bibliotecas de Spring por otra razón. Como verá en el proceso de trabajo práctico con otros tipos de resortes, para todos los demás resortes, Spring IoC se utiliza como marco.
Comenzaremos nuestra introducción a Spring IoC con el término principal: bean. En las palabras mas simples
Un bean es un objeto de clase creado por Spring que se puede incrustar como valor de campo en otro objeto.
¿Quieres palabras más complicadas? Y por favor:
Un bean es un objeto de clase, que es un elemento de programa completo con una función comercial específica o una función Spring interna, cuyo ciclo de vida está controlado por el contenedor bin.
Como ya entendió, para que Shop pueda implementar Shop, Shop debe convertirse en un contenedor. Hay varias maneras de decirle a la aplicación qué objetos tienen el derecho de ser llamados beans, todos los cuales nos llevan al concepto de ApplicationContext.
ApplicationContext es el corazón de la primavera. Como regla, se crea al comienzo de la aplicación ("sube") y controla el ciclo de vida de los beans. Por lo tanto, también se llama contenedor bin.
Estamos llegando a lo principal. ¿Cómo necesitamos reescribir nuestras clases para que Spring IoC y su servidor ApplicationContext sustituyan el campo Shop por el objeto Seller? Así:
@Component public class Shop { }
@Component public class Seller { @Autowired private Shop shop; }
Es simple? Mucho más fácil! Elegante? Bastante Aquí sucedió lo siguiente: la anotación Componente le dijo a Spring que la clase que anotó es un bin. Anotación Autowired le pidió a Spring que sustituyera un valor en el campo que anota. Esta operación se llama inyectar. ¿Qué valor exacto se sustituirá? Más sobre esto más adelante, primero, descubriremos cómo las clases se convierten en bin en general.
Ya sabemos que al comienzo de la aplicación, el tutor de todos los beans de ApplicationContext debe aumentar. Él crea todos los contenedores a la vez. Casi todo El hecho es que, por defecto, cualquier bean tiene el alcance de la propiedad intraspring en el valor singleton. Intraspringovoe, ya que en el sentido literal de la palabra no es un singleton. Es el singleton para spring: cuando se genera el contexto, Spring creará exactamente un objeto bin de la clase especificada. Si desea cambiar este comportamiento, Spring le permite controlar el tiempo de creación del bean y su número para una clase, pero ahora no se trata de eso.
Por lo tanto, al generar ApplicationContext se crean todos los contenedores. Averigüemos exactamente dónde vive el contexto y, lo que es más importante, cómo determina de qué clases crear contenedores. Hay varias opciones, por simplicidad, hablaremos de una de ellas: configuración usando el archivo xml. Aquí hay un ejemplo de ello:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:beans="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="product" class="main.java.Product"></bean> <context:component-scan base-package="main"/> </beans>
Este archivo muestra cómo crear beans de dos maneras. El primero, digamos, es manual. Usted ve, hay una etiqueta de
frijol con una indicación de la clase. Este es el frijol. De todo lo que esté registrado en este archivo con una etiqueta de
bean , se crearán
beans .
La segunda forma es menos detallada. Recuerde, sobre las clases colocamos la anotación Componente. De todas las clases anotadas con esta anotación, se crearán beans. Gracias a esta línea del archivo xml:
<context:component-scan base-package="main"/>
Ella le dice a Spring: escanee todo el paquete principal y, a partir de todo eso, la anotación Componente (u otras anotaciones que son componentes de Componente) se mantendrá activa, crear contenedores. Compacto, ¿no es así? Simplemente decimos qué paquetes contienen las clases a partir de las cuales crear los beans, y anotamos estas clases.
Puede elevar el contexto utilizando el archivo xml con la siguiente línea de código:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
donde beans.xml es la ruta al apodo xml discutido anteriormente.
Con la creación de frijoles resuelto. ¿Cómo llena Spring el campo Tienda al crear un Vendedor? Al generar contexto, se crea un objeto bin de la clase Shop. También se crea un objeto bin de la clase Vendedor; también se anota mediante Componente. Tiene un tipo de tienda anotado por Autowired. La anotación con cables automáticos le dice a spring: debe inyectar el contenedor en este campo. En nuestro caso, solo tenemos un contenedor adecuado para este rol, es decir, el tipo del cual coincide con el tipo del campo: este es un contenedor, una instancia de la clase Shop. Se inyectará en el objeto Vendedor, según sea necesario. Entiendo que ahora las preguntas han subido como gusanos: qué sucederá si Spring no encuentra el bean deseado o encuentra varios adecuados (especialmente teniendo en cuenta que también puede inyectarse a través de la interfaz, y no por clase). La primavera es inteligente, pero requiere lo mismo de nosotros. Necesitamos tener exactamente un bean en el sistema que sea adecuado para cada Autowired, o entrenar a Spring para actuar en tales conflictos (no hablaremos de esto ahora, ya estás cansado, seguro, el artículo está llegando a su fin).
Tenga en cuenta que el vendedor también es un contenedor. Si no se tratara de un contenedor, sino que se creara mediante un nuevo, entonces nada se inyectaría automáticamente en él.
Quizás ahora esté pensando por qué todas estas dificultades son necesarias. Pero imagine que nuestra aplicación no es de 2 clases, sino varios órdenes de magnitud más grandes y que la administración de dependencias ya no es la tarea más trivial.
Quizás ahora piense cuán hermoso, simple y conciso Spring le permite implementar dependencias. Pero imagine que algo salió mal y necesita depurar la aplicación. Y ya no es tan fácil ...
Finalmente, un par de pistas:
- Si ha implementado el proyecto y ahora no sabe cómo obtener un contenedor de la primavera para verlo, haga lo siguiente:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Seller seller = (Seller) context.getBean(Seller.class);
Esta es una forma legal de obtener un contenedor, aunque en las realidades modernas esto generalmente no se hace. Pero para un estudio de caso puedes.
- Como Spring es un marco, debe incluirlo en su proyecto. Creo una aplicación usando maven y agrego dependencias spring-core y spring-context al archivo pom.xml.
Spring IoC contiene enormes oportunidades para crear, configurar e inyectar beans. Examinamos una pequeña parte de la punta del iceberg, una de las formas de trabajar con la primavera, pero espero que hayamos podido verlo detenidamente y tener una idea general de lo que está sucediendo.