Anotaciones de Spring: Anotaciones del Core Framework

    Introducci贸n

    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 @Beanes 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 @Beananotaci贸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 @Requiredanotaci贸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 @Autowiredanotaci贸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 @Componentclases etiquetadas (incluidos los derivados como @Service, @Controllery @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 ProductServiceclase, separ谩ndola de ProductControllersi 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 @Servicebean anotado, pero hablaremos de eso m谩s adelante.

    Tambi茅n hay otros casos de uso para la @Autowiredanotaci贸n.

    @Autowired en Setters

    Muy similar a la @Requiredanotaci贸n, tambi茅n podemos usar @Autowireden 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 @Autowiredanotaci贸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 requiredbandera 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 @Qualifieranotaci贸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 @ComponentScananotaci贸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 @Configurationanotaci贸n.

    Por ejemplo, tenemos un com.Pharos.sh.controllerpaquete 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 @ComponentScananotaci贸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 basePackageque contiene todos nuestros componentes, como com.Pharos.sh. Aunque en algunos casos querr铆amos incluir m煤ltiples basePackageso 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 basePackageses 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 @Lazyanotaci贸n.

    Se puede usar en un nivel de clase anotado como @Componento 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 @Configurationclase como @Lazy:

    @Lazy
    @Configuration
    public class AppConfig {
        // some code
    }
    

    En este caso, todos los beans definidos dentro AppConfigtambi茅n se inicializar谩n de forma diferida.

    @Configuraci贸n

    La @Configurationanotaci贸n est谩 a nivel de clase y le dice a Spring que esta clase contiene uno o m谩s @Beanm茅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 @Valueanotaci贸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 @Valueanotaci贸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 @Valueanotaci贸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 booleans y ints:

    @Value("true")
    private boolean accepted;
    
    @Value("53")
    private int userId;
    

    Propiedades del entorno de lectura

    Digamos que, entre otras propiedades, nuestro application.propertiesarchivo 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_nameno 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 @Valueanotaci贸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 @Valuem茅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 @DependsOnanotaci贸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 @Componento @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 FirstBeanse encuentra antes del segundo y tercero, hemos comentado que depende de la creaci贸n del SecondBeany ThirdBeanpara que funcione correctamente. Al hacer esto, Spring definir谩 primero esos dos y luego FirstBean.

    @Primario

    La @Primaryanotaci贸n se usa a menudo junto con la Qualifieranotaci贸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 @Autowiredanotaci贸n elija entre los beans calificados.

    Sin embargo, esta vez, no necesitamos agregar la @Qualifieranotaci贸n a la @Autowiredanotaci贸n ya que se ha declarado el bean primario / predeterminado:

    @Controller
    public class CompanyController {
        @Autowired
        private Employee employee;
    }
    

    Esto crear谩 una instancia de un Developerbean.

    @Alcance

    La @Scopeanotaci贸n se aplica a nivel de bean y define su visibilidad / ciclo de vida. Si se aplica junto con la @Componentanotaci贸n, define el alcance de las instancias del tipo anotado. Si se usa en un @Beanm茅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 singletonalcance, la aplicaci贸n del alcance del prototipo garantiza una newinstancia del bean anotado cada vez que lo solicitamos.

    @Bean
    @Scope("prototype")
    public Developer developer() {
        return new Developer();  
    }
    

    Solicitud

    El requestalcance 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 @RequestScopeque incluye el proxy por defecto.

    Sesi贸n

    Muy similar al requestalcance, el sessionalcance 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 applicationalcance funciona de manera similar al singletonalcance. El applicationciclo 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 applicationtiene 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 websocketalcance, vinculamos el ciclo de vida de nuestro bean al ciclo de vida de la WebSocketsesi贸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.

    .

    Etiquetas:

    Deja una respuesta

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