Spring framework 5 : AOP Before Advice


Como vimos en el post pasado https://devs4j.com/2019/02/28/spring-framework-5-aop-conceptos-basicos/ existen diferentes tipos de advices, en este post nos enfocaremos en Before Advice.

Para poder seguir estos ejemplos es necesario crear un proyecto spring boot simple.

Creación de un servicio de spring

El primer paso para entender como funcionan los advices será crear un servicio de spring, este objeto será nuestro Target object.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @author raidentrance
 *
 */
@Service
public class HelloWorldService {

	private static final Logger log = LoggerFactory.getLogger(HelloWorldService.class);

	public void print() {
		log.info("Hello world");
	}

}

Como vemos nuestro servicio es solo una clase llamada HelloWorldService con un método llamado print().

Before Advice

En este ejemplo interceptaremos las peticiones a la clase HelloWorldService en su método print utilizando un Before Advice, veamos el siguiente ejemplo:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Aspect
@Component
public class BeforeAdviceExample {

	private static final Logger log = LoggerFactory.getLogger(BeforeAdviceExample.class);

	@Before("execution(* com.devs4j.service.HelloWorldService.print*(..))")
	public void logBefore(JoinPoint joinPoint) {
		log.info("Before advice example");
	}
}

Del código anterior podemos analizar los siguientes puntos:

  • La clase esta anotada con @Component y @Aspect esto permite a spring identificarlo como un bean y como un aspecto.
  • La anotación @Before nos permite utilizar un Before advice.
  • Los advices reciben como parámetro un Pointcut el cual define los objetos que serán afectados por el Advice (Explicaremos Pointcut expression language en otro post).
  • El método recibe como parámetro un objeto que implementa la interfaz JoinPoint, esto nos permite acceder a información del JoinPoint que se interceptó.
  • Lo único que hace nuestro aspecto es imprimir el mensaje Before advice example

Una vez que tenemos listo nuestro aspecto el siguiente paso será probarlo, para esto crearemos la siguiente clase:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.devs4j.service.HelloWorldService;

@SpringBootApplication
public class Devs4jSpringAopApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Devs4jSpringAopApplication.class,
				args);
		HelloWorldService helloWorldService = applicationContext.getBean(HelloWorldService.class);
		helloWorldService.print();
	}

}

Del código anterior podemos analizar los siguientes puntos:

  • Obtenemos un bean del tipo HelloWorldService
  • Ejecutamos el método print()

Salida:

2019-03-01 10:35:26.624  INFO 71997 --- [           main] com.devs4j.aop.BeforeAdviceExample       : Before advice example
2019-03-01 10:35:26.632  INFO 71997 --- [           main] com.devs4j.service.HelloWorldService     : Hello world

Como vemos se imprimió el mensaje Before advice example antes de Hello world, esto nos indica que el aspecto que utiliza before advice se ejecuta antes del método print que se invocó de la clase HelloWorldService.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : AOP Conceptos básicos


AOP (Aspect oriented programming) es un paradigma de programación al igual que la POO (Programación orientada a objetos), en la POO el punto principal de la programación es un objeto mientras que en AOP es un aspecto.

Los aspectos nos ayudan a solucionar problemas llamados crosscutting concerns, para poder adentrarnos a esto primero debemos entender algunos conceptos básicos de AOP:

  • Aspect : Un aspecto es una preocupación o funcionalidad que se aplica a multiples clases, el logging es un buen ejemplo.
  • Join point : Un punto durante la ejecución de un programa como la ejecución de un método o el manejo de una excepción, en Spring Aop siempre será la ejecución de un método.
  • Advice : Será la acción a tomar en un join point específico, existen diferentes tipos de advice “around”, “before” y “after”, se pueden considerar como “interceptores” de nuestros join points.
  • Pointcut : Un predicado que junta un conjunto de join points, para definir este predicado se utiliza AspectJ pointcut expression language.
  • Target object : Un objeto advised por uno o más aspectos, como Spring Aop utiliza proxys este siempre será un objeto proxied.
  • Aop proxy : Un objeto creado por el framework Aop para dar el soporte Aop, en Spring Aop se utiliza proxies dinámicos a través de CGLIB.
  • Weaving : Es el enlace entre los aspectos y los objetos, este se puede hacer de diferentes formas, Spring Aop lo hace en tiempo de ejecución.

Tipos de Advices

Como se menciono anteriormente existen diferentes tipos de advices:

  • Before advice : Este advice se ejecuta antes del join point, no tiene la habilidad de detener la ejecución a menos de que arroje una excepción.
  • After returning : Este advice se ejecuta después del join point, no se ejecuta si hay una excepción.
  • After throwing : Este advise se ejecuta si el método termina por una excepción.
  • After finally : Este advise se ejecuta si el método termina su ejecución de forma normal o por una excepción.
  • Around advice : Este advise rodea la ejecución de un método, puede ejecutar su comportamiento antes, después o incluso si se produce una excepción. También es responsable de determinar si quiere o no proceder con la invocación del método.

Around advice es el advice más poderoso pero es el más general, por esto se recomienda utilizar el más especifico para resolver el problema que necesitamos.

Usos prácticos

Algunos usos prácticos para el uso de Spring Aop son :

  • Logging
  • Seguridad
  • Administración de transacciones
  • Monitoreo de performance
  • Caching
  • Manejo de errores

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : Bean Aware interfaces


Aware interface significa en español interfaz consciente, este tipo de interfaces actúan como listeners para ciertos eventos que suceden en Spring framework.

Las siguientes son las Aware interfaces en Spring framework:

Aware interfaceRecurso objetivo
BeanNameAwareEl nombre del bean de las instancias configuradas
en el contenedor
BeanFactoryAwareEl bean factory actual a través del cual se invoca el
contenedor
ApplicationContextAwareEl application context actual a través del cual
puedes invocar el contenedor
MessageSourceAwareEl message source a través del cual se pueden
resolver mensajes
ApplicationeventPublisherAwareEl even publisher a través del cual se pueden publicar eventos de la aplicación
ResourceLoaderAwareEl resource loader a través del cual puedes cargar recursos externos
EnvironmentAwareLa instancia de Environment asociada con el ApplicationContext

Las Aware Interfaces definen métodos setters los cuales se invocan por Spring después de que las propiedades de Spring se asignaron pero antes de que los método callback (postConstruct y preDestroy) se invoquen.

Ejemplo utilizando BeanNameAware

Para entender como funcionan las aware interfaces crearemos el siguiente bean:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class UserService implements BeanNameAware {

	@Value("fakeUser")
	private String user;

	private static final Logger log = LoggerFactory.getLogger(UserService.class);

	@PostConstruct
	public void init() {
		log.info("Post construct callback {}",user);
	}

	@Override
	public void setBeanName(String name) {
		log.info("Being aware of {} {}", name,user);
	}

	@PreDestroy
	public void destroy() {
		log.info("Pre destroy callback");
	}
}

Al ejecutar la aplicación tendremos la siguiente salida:

2019-02-14 16:01:55.319  INFO 16934 --- [           main] com.devs4j.Devs4jSpringCoreApplication   : Starting Devs4jSpringCoreApplication on m-C02RV1WXG8WP with PID 16934 (/Users/maagapi/Documents/workspaces/devs4j/devs4j-spring-core/target/classes started by maagapi in /Users/maagapi/Documents/workspaces/devs4j/devs4j-spring-core)
2019-02-14 16:01:55.321  INFO 16934 --- [           main] com.devs4j.Devs4jSpringCoreApplication   : No active profile set, falling back to default profiles: default
2019-02-14 16:01:55.686  INFO 16934 --- [           main] com.devs4j.aware.UserService             : Being aware of userService fakeUser
2019-02-14 16:01:55.687  INFO 16934 --- [           main] com.devs4j.aware.UserService             : Post construct callback fakeUser
2019-02-14 16:01:55.833  INFO 16934 --- [           main] com.devs4j.Devs4jSpringCoreApplication   : Started Devs4jSpringCoreApplication in 0.816 seconds (JVM running for 1.11)
2019-02-14 16:01:55.836  INFO 16934 --- [       Thread-2] com.devs4j.aware.UserService             : Pre destroy callback

Este tipo de interfaces se utilizan para logging o para realizar integraciones con código legado, en la mayoría de los casos debemos evitar utilizarlas debido a que acoplan nuestra aplicación a Spring framework.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : Spring Expression Language SpEL


Spring expression language (SpEL) es un lenguaje de expresiones que permite realizar operaciones sobre la información en tiempo de ejecución, en el post anterior se utilizó para leer información de un archivo .properties, en este post hablaremos más sobre expression language en detalle.

Los operadores disponibles en SpEL son los siguientes:

Operadores aritmeticos+, -, *, /, %, ^, div, mod
Relacionales <, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
Lógicosand, or, not, &&, ||, !
Condicionales?:
Expresiones regularesMatchers

A continuación mostraremos como utilizarlos en una aplicación de spring.

SpelExpressionParser

Antes de iniciar, el primer paso será aprender a utilizar la clase SpelExpressionParser la cual nos permite evaluar expresiones sin necesidad de iniciar el contexto de Spring framework, a continuación se muestra como crearlo:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * @author raidentrance
 *
 */
public class SpelExpressionApplication {

	private static final Logger log = LoggerFactory.getLogger(SpelExpressionApplication.class);

	public static void main(String[] args) {
		ExpressionParser expressionParser = new SpelExpressionParser();
		Expression expression = expressionParser.parseExpression("'Hi from devs4j'");
		log.info("String expression {}",expression.getValue());
		
	}
}

Analizando el código anterior podemos ver lo siguiente :

  • SpelExpressionParser nos permite evaluar expresiones de spring SpEL
  • El método Expression parseExpression(String expression) recibe como parámetro una expresión de spring y devuelve un objeto de tipo Expression.
  • La clase Expression contiene un método llamado Object getValue() el cuál devuelve el resultado de la expresión.

Ejemplos básicos de expresiones

Una vez que entendimos como evaluar expresiones SpEL, el siguiente paso será ver algunos ejemplos:

Uso de Strings

public static void main(String[] args) {
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("'Hi'.concat('from devs4j')");
	log.info("Concat expression {}", expression.getValue());
	expression = expressionParser.parseExpression("'Hi from devs4j'.toUpperCase()");
	log.info("To upper case expression {}", expression.getValue());
	expression = expressionParser.parseExpression("'Hi from devs4j'.length()");
	log.info("Get length expression {}", expression.getValue());

}

La expresión anterior concatena los Strings “Hi” y “from devs4j” al ejecutarlo el resultado será:

11:05:36.022 [main] INFO com.devs4j.spel.SpelExpressionApplication - Concat expression Hifrom devs4j
11:05:36.026 [main] INFO com.devs4j.spel.SpelExpressionApplication - To upper case expression HI FROM DEVS4J
11:05:36.026 [main] INFO com.devs4j.spel.SpelExpressionApplication - Get length expression 14

Operadores aritméticos

private static final Logger log = LoggerFactory.getLogger(SpelExpressionApplication.class);

public static void main(String[] args) {
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("10 + 20");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("10 - 20");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("10 * 20");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("20 / 10");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("20 mod 10");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("2 ^ 3");
	log.info("Arithmetic expression {}", expression.getValue());

	expression = expressionParser.parseExpression("(2 ^ 3) * 2 + 24");
	log.info("Arithmetic expression {}", expression.getValue());

}

La salida del código anterior sería:

11:17:42.464 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 30
11:17:42.468 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression -10
11:17:42.469 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 200
11:17:42.469 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 2
11:17:42.470 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 0
11:17:42.470 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 8
11:17:42.470 [main] INFO com.devs4j.spel.SpelExpressionApplication - Arithmetic expression 40

Operadores relacionales

public static void main(String[] args) {
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("10 < 20");
	log.info("Relational expression {}", expression.getValue());

	expression = expressionParser.parseExpression("10 > 20");
	log.info("Relational expression {}", expression.getValue());

	expression = expressionParser.parseExpression("10 == 20");
	log.info("Relational expression {}", expression.getValue());

	expression = expressionParser.parseExpression("10 != 20");
	log.info("Relational expression {}", expression.getValue());

}

Salida del código anterior:

11:19:59.557 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression true
11:19:59.561 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression false
11:19:59.562 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression false
11:19:59.562 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression true

Operadores lógicos

public static void main(String[] args) {
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("100 > 20 && 100 < 10000");
	log.info("Relational expression {}", expression.getValue());

	expression = expressionParser.parseExpression("100 < 20 || 100 < 10000");
	log.info("Relational expression {}", expression.getValue());

	expression = expressionParser.parseExpression("!(100 < 20) ");
	log.info("Relational expression {}", expression.getValue());
}

Salida:

11:22:29.569 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression true
11:22:29.573 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression true
11:22:29.573 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression true

Operadores condicionales

private static final Logger log = LoggerFactory.getLogger(SpelExpressionApplication.class);

public static void main(String[] args) {
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("(10 ==20) ? 'Hi':'Adios'");
	log.info("Conditional expression {}", expression.getValue());
}

Salida:

11:24:44.866 [main] INFO com.devs4j.spel.SpelExpressionApplication - Relational expression Adios

Uso de expresiones regulares en SpEL

Veamos el siguiente modelo:

class User {
	private String username;
	private String password;

	public User(String username, String password) {
		this.username = username;
		this.password = password;
	}

	// Getters y setters
}
public static void main(String[] args) {

	User user = new User("raidentrance", "devs4jRules");
	
	ExpressionParser expressionParser = new SpelExpressionParser();
	Expression expression = expressionParser.parseExpression("username matches '[a-zA-Z]+'");
	log.info("Regex expression {}", expression.getValue(user));
	
	expression = expressionParser.parseExpression("password matches '[a-zA-Z]+'");
	log.info("Regex expression {}", expression.getValue(user));
}

Salida:

11:37:49.944 [main] INFO com.devs4j.spel.SpelExpressionApplication - Regex expression true
11:37:49.947 [main] INFO com.devs4j.spel.SpelExpressionApplication - Regex expression false

Estos son solo algunos ejemplos sobre el uso de Expression language en Spring, cabe aclarar que es posible utilizarlo también con la anotación @Value(String value) lo cual lo hace un lenguaje muy poderoso y fácil de utilizar en Spring.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales

 https://www.facebook.com/devs4j/ 

https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : Leer información de archivos .properties


Una tarea común al hacer aplicaciones utilizando spring es leer configuraciones de archivos de tipo .properties, en este ejemplo tomaremos como base el post Spring framework 5 : Uso de @Autowire para listas de objetos y lo modificaremos para leer el valor de las figuras de un archivo properties en lugar de inyectarlo directamente.

Paso 1 Creación del archivo properties

El primer paso será crear el archivo .properties que contendrá los valores de radio, ancho, largo y lado de las figuras que construiremos:

/src/main/resources/areas.properties

circle.radius = 10.0
rectangle.width = 10.0
rectangle.height = 5.0
square.side=10.0

Paso 2 Carga de properties a spring

Una vez que se creó el archivo de propiedades el siguiente paso será cargar esas propiedades a spring para esto crearemos la siguiente clase de configuración:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

/**
 * @author raidentrance
 *
 */
@Configuration
@PropertySource("classpath:areas.properties")
public class FigurePropertyCopnfiguration {

	@Bean
	public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
}

Como se puede ver en la anotación @PropertySource se define el archivo .properties del cuál se cargaran las propiedades.

Paso 3 Modificar los beans para utilizar las propiedades

Una vez que se cargaron las propiedades a spring el siguiente paso será modificar nuestras clases, en el ejemplo anterior se utilizó @Value(“10.0”) lo cual inyectaba el valor de 10 a la referencia, ahora en lugar de hacer eso haremos un @Value(“${circle.radius:0}”) lo cual tomará el valor de la propiedad circle.radius y lo inyectará en nuestra variable, veamos como queda el código:

/**
 * @author raidentrance
 *
 */
public abstract class Figure {

	public abstract double getArea();

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Circle extends Figure {

	private double radius;

	private static final Logger log = LoggerFactory.getLogger(Circle.class);

	public Circle(@Value("${circle.radius:0}") double radius) {
		this.radius = radius;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a circle with radius {}", radius);
		return Math.pow(Math.PI * radius, 2);
	}

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Rectangle extends Figure {

	private double width;

	private double height;

	private static final Logger log = LoggerFactory.getLogger(Rectangle.class);

	public Rectangle(@Value("${rectangle.width:0}") double width, @Value("${rectangle.height:0}") double height) {
		this.width = width;
		this.height = height;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a rectangle with with {} and height", width, height);
		return width * height;
	}

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Square extends Figure {

	private double side;
	
	private static final Logger log = LoggerFactory.getLogger(Square.class);

	public Square(@Value("${square.side:0}") double side) {
		this.side = side;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a square with side {}", side);
		return Math.pow(side, 2);
	}

}

La siguiente sintaxis @Value(“${square.side:0}”) significa toma el valor de la propiedad square.side, en caso de que no exista se asignará el valor 0.

El uso de propiedades es muy común debido a que es posible cambiar las configuraciones del código sin tener que re compilar el código.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : Uso de @Autowire para listas de objetos


En ejemplos anteriores se explicó como inyectar objetos en spring utilizando la anotación @Autowired para objetos simples, en este post explicaremos como inyectar listas de objetos.

Paso 1 Crear las clases a inyectar

El primer paso será crear una lista de clases a inyectar, en este caso tendremos una clase padre y multiples clases hijas, veamos el siguiente código:

/**
 * @author raidentrance
 *
 */
public abstract class Figure {

	public abstract double getArea();

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Circle extends Figure {

	private double radius;

	private static final Logger log = LoggerFactory.getLogger(Circle.class);

	public Circle(@Value("10.0") double radius) {
		this.radius = radius;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a circle with radius {}", radius);
		return Math.pow(Math.PI * radius, 2);
	}

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Square extends Figure {

	private double side;
	
	private static final Logger log = LoggerFactory.getLogger(Square.class);

	public Square(@Value("10.0") double side) {
		this.side = side;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a square with side {}", side);
		return Math.pow(side, 2);
	}

}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class Rectangle extends Figure {

	private double width;

	private double height;

	private static final Logger log = LoggerFactory.getLogger(Rectangle.class);

	public Rectangle(@Value("10.0") double width, @Value("5.0") double height) {
		this.width = width;
		this.height = height;
	}

	@Override
	public double getArea() {
		log.info("Calculating the are of a rectangle with with {} and height", width, height);
		return width * height;
	}

}

Se crearon las siguientes clases:

  • Figure : Clase abstracta que será padre de las demás clases, define el método abstracto double getArea()
  • Circle : Define el atributo radio y utiliza la anotación @Value para asignarle el valor de 10.0
  • Square : Define el atributo lado y utiliza la anotación @Value para asignarle el valor de 10.0
  • Rectangle : Define los atributos ancho y alto y utiliza la anotación @Value para asignarles el valor de 10.0 y 5.0.

Las 3 implementaciones Circle, Square y Rectangle implementan el método getArea() definido en la clase Figure.

Inyectando los beans en una referencia de tipo List

Una vez que definimos los beans con sus valores el siguiente paso será inyectarlos en una referencia de tipo List, veamos la siguiente clase:

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class AreaCalculator {

	@Autowired
	private List<Figure> figures;

	public double getSumOfAreas() {
		double totalArea = 0.0;
		for (Figure figure : figures) {
			totalArea += import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class AreaCalculator {

	@Autowired
	private List<Figure> figures;

	public double getSumOfAreas() {
		double totalArea = 0.0;
		for (Figure figure : figures) {
			totalArea += figure.getArea();
		}
		return totalArea;
	}
}
.getArea();
		}
		return totalArea;
	}
}

Como se puede ver la clase AreaCalculator tiene un método que suma el área de todas las figuras, para esto debe inyectar un List<Figure>, con esto Spring inyectará todas las implementaciones de Figure.

Ejecutando la aplicación

El último paso será modificar la clase aplicación para ejecutar el método getSumOfAreas() como se muestra en la siguiente clase:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.devs4j.lists.AreaCalculator;

@SpringBootApplication
public class Devs4jSpringCoreApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Devs4jSpringCoreApplication.class,
				args);

		AreaCalculator areaCalculator = applicationContext.getBean(AreaCalculator.class);
		System.out.println(areaCalculator.getSumOfAreas());
	}

}

Al ejecutarlo la salida será la siguiente :

2019-02-07 12:01:50.366  INFO 96221 --- [           main] com.devs4j.Devs4jSpringCoreApplication   : Started Devs4jSpringCoreApplication in 1.224 seconds (JVM running for 1.501)
 2019-02-07 12:01:50.368  INFO 96221 --- [           main] com.devs4j.lists.Circle                  : Calculating the are of a circle with radius 10.0
 2019-02-07 12:01:50.369  INFO 96221 --- [           main] com.devs4j.lists.Rectangle               : Calculating the are of a rectangle with with 10.0 and height
 2019-02-07 12:01:50.369  INFO 96221 --- [           main] com.devs4j.lists.Square                  : Calculating the are of a square with side 10.0
 1136.960440108936

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : Uso de los scopes (prototype y singleton) utilizando la anotación @Scope


El scope de un bean define su ciclo de vida, en los posts anteriores hemos creado beans pero no hemos definido su scope, al hacer esto Spring le asigna uno por defecto, a continuación se muestran los scopes disponibles:

ScopeDescripción
SingletonCrea una sola instancia del bean por contenedor de Spring
PrototypeCrea una nueva instancia cada vez que se solicita
RequestCrea una nueva instancia por cada petición HTTP,
solo se puede utilizar en una aplicación web
SessionCrea una nueva instancia por cada sesión HTTP
ApplicationCrea una nueva instancia por cada ServletContext

En este post nos enfocaremos en los scopes Singleton y Prototype.

Scope singleton

El scope singleton es el scope por defecto en spring, veamos el siguiente bean:

import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Component
public class SingletonScopeBean {
}

Ahora veamos la siguiente clase aplicación:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.devs4j.scopes.SingletonScopeBean;

@SpringBootApplication
public class SpringExampleApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringExampleApplication.class, args);

		SingletonScopeBean singletonBean = applicationContext.getBean(SingletonScopeBean.class);

		SingletonScopeBean secondSingletonBean = applicationContext.getBean(SingletonScopeBean.class);

		System.out.println(singletonBean.equals(secondSingletonBean));
	}

}

La salida será la siguiente:

true

Podemos ver que tenemos 2 beans singletonBean y secondSingletonBean y al llamar el método equals la salida es true, indicando que es el mismo objeto.

Scope prototype

El scope prototype indica que se creará un bean nuevo cada que se mande llamar, por esto re utilizaremos el bean anterior y solo cambiaremos su scope como se muestra a continuación:

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeScopeBean {

}

Re utilizaremos la clase aplicación:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.devs4j.scopes.PrototypeScopeBean;

@SpringBootApplication
public class SpringExampleApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringExampleApplication.class, args);

		PrototypeScopeBean prototypeBean = applicationContext.getBean(PrototypeScopeBean.class);

		PrototypeScopeBean secondPrototypeBean = applicationContext.getBean(PrototypeScopeBean.class);

		System.out.println(prototypeBean.equals(secondPrototypeBean));
	}

}

La salida será la siguiente:

false

Esto se debe a que cada vez que se mande llamar el método getBean se creará un bean nuevo, es por esto que al mandar llamar al método equals el resultado será false.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com