Introducci贸n
Contenido
El Spring Framework es un marco muy robusto, lanzado en 2002. Sus caracter铆sticas principales se puede aplicar a las aplicaciones de Java convencionales o extenderse a aplicaciones web modernas, complejas.
Dado que se actualiza constantemente y sigue nuevos paradigmas de arquitectura y programaci贸n, ofrece soporte para muchos otros marcos que trabajan de la mano con 茅l.
Con una gama tan amplia de funcionalidades, es normal que nos presente algunas anotaciones nuevas, que son una parte clave del desarrollo de aplicaciones Spring.
La configuraci贸n de Spring es totalmente personalizable, lo que originalmente se hizo a trav茅s de archivos de configuraci贸n XML. Sin embargo, este enfoque se ha vuelto obsoleto y la mayor铆a de las personas hoy en d铆a recurren a la configuraci贸n de anotaciones.
Dicho esto, esta serie de art铆culos tiene como objetivo desentra帽ar las opciones que usted, como desarrollador, tiene para configurar y usar el marco Spring:
- Anotaciones de Spring Framework: @RequestMapping y sus variantes
- Spring Annotations: anotaciones principales
- Spring Annotations: anotaciones de Spring Cloud
- Spring Annotations: Prueba de anotaciones
Nota : Este art铆culo asume que est谩 familiarizado con el principio de Inversi贸n de Control de Spring.
Anotaciones principales
Echemos un vistazo a las anotaciones centrales que componen casi todas las aplicaciones Spring:
@Frijol
A @Bean
es un objeto troncal en Spring Framework. Todo se reduce a JavaBeans: clases que encapsulan objetos en uno solo. Son un tipo de POJO (Plain Old Java Object).
Todos los JavaBeans deben ser Serializable
, todos los campos deben ser privados, todos los campos deben tener setters y getters, debe haber un constructor sin argumentos y los campos son accedidos exclusivamente por el constructor o los m茅todos getter / setter:
public class Developer implements java.io.Serializable {
private int id;
private String name;
public Developer() {}
public void setId(int id) {this.id = id;}
public int getId() {return id;}
public void setName(String name) {this.name = name;}
public String getName() {return name;}
}
En t茅rminos de Spring, los beans son instanciados y administrados por Spring IoC Container. Son simplemente instancias de objetos administradas por Spring.
Para que Spring sepa qu茅 instancias de objetos debe administrar, simplemente marcamos los m茅todos en los que las instanciamos con la @Bean
anotaci贸n.
Cuando se encuentre este m茅todo, se ejecutar谩 y el valor devuelto se guardar谩 dentro de BeanFactory
:
@Configuration
public class ConfigurationClass {
@Bean
public Developer developer() {
return new Developer();
}
}
Esto es lo mismo que usar el antiguo enfoque XML para registrar un bean:
<beans>
<bean name="developer" class="com.Pharos.sh.Developer"/>
</beans>
Ahora, para inyectar este bean como una dependencia en otro bean, simplemente tenemos otro bean que llama al m茅todo del bean desarrollador:
@Configuration
public class ConfigurationClass() {
@Bean
public Manager manager() {
return new Manager(developer());
}
@Bean
public Developer developer() {
return new Developer();
}
}
@Necesario
La @Required
anotaci贸n se utiliza en constructores y m茅todos de establecimiento. Como sugiere el nombre, le dice a Spring que estos campos son necesarios para que el bean se inicialice correctamente.
Si los campos no se completan en el momento de la configuraci贸n, el bean no se inicializar谩, lo que dar谩 como resultado una excepci贸n y la aplicaci贸n no podr谩 compilarse:
public class Developer implements java.io.Serializable {
private int id;
private String name;
public Developer() {}
@Required
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Para completar un campo en tiempo de configuraci贸n como este, asignamos los nombres de propiedad a trav茅s de XML:
<bean class="com.Pharos.sh.Develope>
<property name="name" value="David"/>
</bean>
@Autowired
La @Autowired
anotaci贸n se utiliza para un mayor control sobre la inyecci贸n de dependencia. Se usa para conectar un bean a otro sin instanciar el anterior.
Nuevamente, en lugar de conectar las dependencias a trav茅s de XML, que era engorroso, simplemente marcamos nuestras dependencias como @Autowired
. Basado en nuestra clase base, donde se encuentran todos nuestros componentes, Spring hace todo el cableado por nosotros.
Para declarar el paquete base de nuestros componentes, simplemente podemos agregar una etiqueta al archivo de contexto de nuestra aplicaci贸n:
<context:component-scan base-package="com.Pharos.sh.basePackage"/>
Todas las @Component
clases etiquetadas (incluidos los derivados como @Service
, @Controller
y @Repository
) se registrar谩n como beans que son elegibles para autowiring.
@Autowired en propiedades
En lugar de la instanciaci贸n expl铆cita e imperativa:
public class ProductController {
private ProductService productService = new ProductService();
public void someMethod() {
List<Product> productList = productService.getProductList();
}
}
Usamos un enfoque declarativo:
public class ProductController {
@Autowired
private ProductService productService;
public void someMethod() {
List<Product> productList = productService.getProductList();
}
}
En esta implementaci贸n, nunca creamos realmente una instancia de la ProductService
clase, separ谩ndola de ProductController
si deseamos probarla.
Por supuesto, para conectar autom谩ticamente un campo, debe estar registrado como un bean en el contenedor Spring IoC. En nuestro caso, es un @Service
bean anotado, pero hablaremos de eso m谩s adelante.
Tambi茅n hay otros casos de uso para la @Autowired
anotaci贸n.
@Autowired en Setters
Muy similar a la @Required
anotaci贸n, tambi茅n podemos usar @Autowired
en setters:
public class ProductController {
private ProductService productService;
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
}
Al conectar autom谩ticamente un establecedor como este, no es necesario completarlo a trav茅s de XML.
Esta es la llamada inyecci贸n de dependencia basada en setter .
@Autowired en constructores
La @Autowired
anotaci贸n tambi茅n se puede utilizar en constructores:
public class ProductService {
private ProductDao productDao;
@Autowired
public ProductService(ProductDao productDao) {
this.productDao = productDao;
}
}
Esta es la llamada inyecci贸n de dependencia basada en constructor .
La bandera requerida
Al marcar un bean como @Autowired
, Spring espera que est茅 disponible al construir las otras dependencias. Si no, seremos recibidos con una excepci贸n y una compilaci贸n fallida.
Si no puede garantizar que el bean estar谩 disponible, o si no siempre es necesario, puede usar la required
bandera para marcarlo como opcional:
public class ProductController {
@Autowired(required = false)
private ProductService productService;
}
De esta forma, si el bean de servicio del producto no est谩 disponible, todo funcionar谩 sin problemas.
@Calificatorio
La @Qualifier
anotaci贸n se usa para aclarar los casos en los que nos gustar铆a conectar autom谩ticamente m谩s de un bean del mismo tipo.
Por ejemplo, en una empresa, lo m谩s probable es que tengamos m谩s de un empleado, y cada empleado tiene su puesto respectivo: desarrollador, desarrollador l铆der, gerente, CEO, etc.
@Component
public class Developer implements Employee {}
@Component
public class Manager implements Employee {}
Si tuvi茅ramos que conectar autom谩ticamente un empleado, ser铆a ambiguo en cuanto a qu茅 bean queremos conectar autom谩ticamente:
@Controller
public class CompanyController {
@Autowired
private Employee employee;
}
Nos recibir铆a un error:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.Pharos.sh.employee] is defined:
expected single matching bean but found 2: [developer, manager]
Para evitar tal situaci贸n, agregamos calificadores:
@Component
@Qualifier("developer")
public class Developer implements Employee {}
@Component
@Qualifier("manager")
public class Manager implements Employee {}
Y cuando se conecta autom谩ticamente:
@Controller
public class CompanyController {
@Autowired
@Qualifier("developer")
private Employee employee;
}
Esto aclara qu茅 bean nos gustar铆a conectar autom谩ticamente y el c贸digo se ejecuta bien.
@ComponentScan
Una anotaci贸n crucial para Spring es la @ComponentScan
anotaci贸n. Especifica qu茅 paquetes contienen clases que est谩n anotadas. De esa manera, Spring sabe qu茅 clases necesita administrar y siempre se usa junto con la @Configuration
anotaci贸n.
Por ejemplo, tenemos un com.Pharos.sh.controller
paquete que contiene todos nuestros controladores donde cada clase est谩 anotada @Controller
. Para que Spring sepa que este paquete contiene componentes que necesitan administraci贸n, usamos la @ComponentScan
anotaci贸n y agregamos el paquete.
De lo contrario, tendr铆amos que registrar cada bean individualmente, lo que ser铆a engorroso e imposible de escalar.
En muchos casos, simplemente definimos uno basePackage
que contiene todos nuestros componentes, como com.Pharos.sh
. Aunque en algunos casos querr铆amos incluir m煤ltiples basePackages
o basePackageClasses
:
@Configuration
@ComponentScan(basePackage = "com.Pharos.sh")
public class SomeApplication {
// some code
}
Si nos gustar铆a definir varios paquetes base:
@Configuration
@ComponentScan(basePackage = {"com.package1", "com.package2})
public class SomeApplication {
// some code
}
Una alternativa de tipo seguro para basePackages
es basePackageClasses
:
@Configuration
@ComponentScan(basePackageClasses = Developer.class)
public class SomeApplication {
// some code
}
Nota : Si no se define ning煤n paquete base, el paquete en el que se encuentra la clase se utilizar谩 como paquete base.
@Perezoso
Por defecto, los beans y componentes se inicializan con entusiasmo. Si quisi茅ramos cambiar ese comportamiento, podemos hacerlo mediante la @Lazy
anotaci贸n.
Se puede usar en un nivel de clase anotado como @Component
o en un nivel de m茅todo anotado como @Bean
.
Si se anota, el componente / bean no se inicializar谩 hasta que otro bean lo haga referencia expl铆citamente y sea necesario para que la aplicaci贸n se ejecute sin problemas:
@Lazy
@Bean
class SomeResource {}
Tambi茅n podr铆amos marcar una @Configuration
clase como @Lazy
:
@Lazy
@Configuration
public class AppConfig {
// some code
}
En este caso, todos los beans definidos dentro AppConfig
tambi茅n se inicializar谩n de forma diferida.
@Configuraci贸n
La @Configuration
anotaci贸n est谩 a nivel de clase y le dice a Spring que esta clase contiene uno o m谩s @Bean
m茅todos y puede ser procesada por el contenedor Spring para generar definiciones de frijoles.
Esta es una de las razones por las que los desarrolladores pudieron dejar de usar la configuraci贸n basada en XML y la simplicidad de la anotaci贸n hace que la configuraci贸n basada en Java sea preferible.
@Configuration
public class AppConfig {
@Bean
public SomeBean someBean() {
// Instantiation, configuration, returning the bean
}
@Valor
La @Value
anotaci贸n tiene bastantes casos de uso en Spring y garantiza un art铆culo para s铆 misma. Intentar茅 ser breve y cubrir los casos de uso m谩s comunes y obvios en este caso.
Puede utilizarse para:
- Asignar valores predeterminados a los campos
- Lectura de variables de entorno
- Uso de expresiones de Spring Expression Language (SpEL)
- Valores predeterminados para par谩metros si se usan dentro de un m茅todo / constructor
Dicho esto, repasemos todos estos casos de uso uno por uno.
Valores de campo predeterminados
Si desea asignar un valor predeterminado a un campo, la @Value
anotaci贸n es bastante sencilla:
@Value("Hello World!")
private String helloString;
Aunque no creamos esta cadena ni le asignamos un valor expl铆citamente, lo hemos hecho a trav茅s de la anotaci贸n.
La @Value
anotaci贸n est谩 pensada para usarse con Strings. Si intenta aplicarlo a otro tipo, funcionar谩 solo si Spring puede convertir f谩cilmente entre los dos, como boolean
s y int
s:
@Value("true")
private boolean accepted;
@Value("53")
private int userId;
Propiedades del entorno de lectura
Digamos que, entre otras propiedades, nuestro application.properties
archivo contiene algunas variables de entorno:
sa.website_name = Stack Abuse
Por ejemplo, leamos esta propiedad y la asignamos a un String en nuestra clase de configuraci贸n. Para hacer esto, tambi茅n necesitamos definir la fuente de la propiedad:
@PropertySource("classpath:application.properties")
@Configuration
public class AppConfig {
@Value("${sa.website_name}")
private String websiteName;
}
En t茅rminos generales, ${...}
se utiliza como marcador de posici贸n de propiedad en Spring. Probablemente ya est茅 familiarizado con esto si ha incursionado en las tecnolog铆as Spring.
Si la propiedad no est谩 disponible o definida, podr铆amos tener un problema. En este caso, podemos definir valores predeterminados para los marcadores de posici贸n en caso de que no est茅n definidos correctamente:
@PropertySource("classpath:application.properties")
@Configuration
public class AppConfig {
@Value("${sa.website_name}:Backup Value")
private String websiteName;
}
De esta forma, si sa.website_name
no existe, el valor asignado al String ser谩 Backup Value
.
Usando SPEL
Similar a la sintaxis del marcador de posici贸n, Spring Expression Language (SpEL) usa la #{...}
sintaxis para almacenar expresiones:
@Value("#{systemProperties['java.home']}")
private String someValue;
Si decidimos incluir algunas propiedades que podr铆an no estar disponibles, nuevamente estar铆amos en un problema. Para evitar estos casos, tambi茅n podemos definir valores de “copia de seguridad” predeterminados para los SpEL:
@Value("#{systemProperties['unknownproperty'] ?: 'Backup Value'}")
private String someValue;
Valores de par谩metros predeterminados
Si se aplica a un m茅todo, la @Value
anotaci贸n asignar谩 el valor predeterminado a todos los par谩metros del m茅todo:
@Value("Hello")
public String hello(String str1, String str2) {
return str1 + str2;
}
Este m茅todo imprimir铆a:
HelloHello
Por otro lado, si aplicamos el @Value
m茅todo tanto a un m茅todo como a un par谩metro, al par谩metro se le asignar谩 el nuevo valor:
@Value("Hello")
public String hello(String str1, @Value("World") String str2) {
return str1 + str2;
}
La salida en este caso ser铆a:
HelloWorld
@DependsOn
Si un bean depende de otros beans para una correcta instanciaci贸n, Spring puede garantizar que todos los beans de los que depende se crear谩n antes que 茅l. Sin embargo, necesitamos especificar cu谩les usando la @DependsOn
anotaci贸n.
La anotaci贸n acepta una matriz de cadenas que corresponden a los nombres de los beans en cuesti贸n. Esto significa que puede pasar cualquier nombre de bean v谩lido como argumento, siempre que est茅 debidamente anotado con una anotaci贸n @Component
o @Bean
.
@Configuration
public class AppConfig {
@Bean("firstBean")
@DependsOn(value = {"secondBean", "thirdBean"})
public FirstBean firstBean() {
return new FirstBean();
}
@Bean("secondBean")
public SecondBean secondBean() {
return new SecondBean();
}
@Bean("thirdBean")
public ThirdBean thirdBean() {
return new ThirdBean();
}
}
Aunque FirstBean
se encuentra antes del segundo y tercero, hemos comentado que depende de la creaci贸n del SecondBean
y ThirdBean
para que funcione correctamente. Al hacer esto, Spring definir谩 primero esos dos y luego FirstBean
.
@Primario
La @Primary
anotaci贸n se usa a menudo junto con la Qualifier
anotaci贸n. Se utiliza para definir el bean “predeterminado” para el cableado autom谩tico cuando no hay m谩s informaci贸n disponible.
Da prioridad al bean anotado, si hay m谩s de un bean del mismo tipo, como su nombre lo indica:
@Component
@Qualifier("developer")
@Primary
public class Developer implements Employee {}
@Component
@Qualifier("manager")
public class Manager implements Employee {}
Este es el mismo problema que encontramos en la parte anterior del art铆culo, donde definimos un calificador para permitir que la @Autowired
anotaci贸n elija entre los beans calificados.
Sin embargo, esta vez, no necesitamos agregar la @Qualifier
anotaci贸n a la @Autowired
anotaci贸n ya que se ha declarado el bean primario / predeterminado:
@Controller
public class CompanyController {
@Autowired
private Employee employee;
}
Esto crear谩 una instancia de un Developer
bean.
@Alcance
La @Scope
anotaci贸n se aplica a nivel de bean y define su visibilidad / ciclo de vida. Si se aplica junto con la @Component
anotaci贸n, define el alcance de las instancias del tipo anotado. Si se usa en un @Bean
m茅todo, el alcance se aplica a la instancia devuelta.
Hay dos 谩mbitos b谩sicos, con otros cuatro para aplicaciones compatibles con la web:
- 煤nico
- prototipo
- solicitud
- sesi贸n
- solicitud
- websocket
Alcance Singleton
Si no se utiliza ning煤n otro nombre de 谩mbito, el valor predeterminado es singleton . Un singleton
谩mbito garantiza solo una instancia de la instancia devuelta del m茅todo anotado. El objeto se guardar谩 en el contenedor Spring y se almacenar谩 en cach茅, lo que permitir谩 su uso en cualquier lugar de la aplicaci贸n:
@Bean
@Scope("singleton")
public CompanyCEO companyCEO() {
return new CompanyCEO();
}
Prototipo
Lo opuesto al singleton
alcance, la aplicaci贸n del alcance del prototipo garantiza una new
instancia del bean anotado cada vez que lo solicitamos.
@Bean
@Scope("prototype")
public Developer developer() {
return new Developer();
}
Solicitud
El request
alcance garantiza la instanciaci贸n de un solo bean para cada solicitud HTTP:
// This method will be called on every HTTP request
@Bean
@Scope("request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public SetupClass someSetup() {
// Run some setup on each http request
}
Una alternativa ser铆a utilizar la anotaci贸n 4.3 @RequestScope
que incluye el proxy por defecto.
Sesi贸n
Muy similar al request
alcance, el session
alcance instanciar谩 el bean anotado con un ciclo de vida dependiente de la sesi贸n HTTP.
// This method will be called on every HTTP session
@Bean
@Scope("session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public SetupClass someSetup() {
// Run some setup on each http session
}
Solicitud
El application
alcance funciona de manera similar al singleton
alcance. El application
ciclo de vida de un bean con 谩mbito depende de la aplicaci贸n, o mejor dicho, del ServletContext
.
La principal diferencia entre esos dos es el hecho de que application
tiene un alcance m谩s amplio en el sentido de que puede expandirse a otras aplicaciones que se ejecutan en el mismo ServletContext
.
@Scope("application")
@Component
public class Application {}
Nuevamente, a partir de 4.3, puede reemplazar esta anotaci贸n con @ApplicationScope
.
WebSocket
Si usamos el websocket
alcance, vinculamos el ciclo de vida de nuestro bean al ciclo de vida de la WebSocket
sesi贸n de.
La primera vez que se llama, se crea una instancia del bean y se almacena para su uso posterior dentro de la misma sesi贸n:
// This method will be called on every websocket session
@Bean
@Scope("websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public SetupClass someSetup() {
// Run some setup on each websocket session
}
Conclusi贸n
El marco Spring es un marco poderoso y robusto que realmente cambi贸 el juego cuando se trata de desarrollar aplicaciones web. Entre su gran cantidad de proyectos, es una buena idea comenzar con el marco central y desarrollarlo.
El marco central nos presenta varias anotaciones que hacen nuestra vida m谩s f谩cil y productiva. Manejar estas anotaciones es una necesidad para todos los desarrolladores de Java / Spring.
.