Inyección de dependencias en Spring

By | 22 agosto 2013

Ya contamos con un tutorial básico de inyección de dependencias en Spring, así que vamos a aprovechar esta entrada del manual para enlazar a la entrada antigua en lo básico y explicar en esta alguna cosilla más que podemos hacer con esta característica de Spring.

Anteriormente, en ¿Que es un Spring Bean? hicimos un ejemplo con una clase, SillyClass, dicha clase la anotábamos con @Service y accedíamos a sus métodos desde una vista (JSP) de la aplicación.

Analicemos que beans existen en este momento en el contenedor de esa aplicación. Para ello inyectaremos con @Autowired en el controlador de la aplicación el ApplicationContext de la aplicación que Spring reconoce e inyecta, y pasaremos a hacer uso del método getBeanDefinitionNames().

CONTENT BEANS:
--------------
mvcContentNegotiationManager
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.format.support.FormattingConversionServiceFactoryBean
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.handler.MappedInterceptor
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
mainController
com.pj.springapp.SillyClass
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor

Si elimináramos de @Service el nombre por defecto de este “sillyService“, se vería tal y como lo vemos en la lista anterior. Pero como decidimos darle un nombre, en la lista nos aparecerá dicho bean con el nombre suministrado en @Service.

Como en cualquier lugar, un identificador personal sirve para identificar mejor algo en concreto, de este modo, si no hubiéramos especificado un nombre, Spring inyectaría con @Autowired el tipo de clase, existiendo una del mismo tipo.

¿Pero que ocurre si tengo varios beans de la misma clase?. La respuesta es sencilla, que debemos utilizar los identificadores para poder hacer uso de ellos.

Aquí tenemos nuestra antigua clase @Service SillyClass con id “sillyService“.

@Service("sillyService")
public class SillyClass {

    private String string = "Silly string.";

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

}

Y para no redundar, vamos a utilizar applicationContext.xml para crear otro bean de la misma clase, que llamaremos “sillyService2” y al que le vamos a inyectar un nuevo valor para su atributo string.

    <bean id="sillyService2" class="com.pj.springapp.SillyClass" >
        <property name="string" value="Silly String 2." />
    </bean>

Ahora nuestro contenedor de beans quedara así.

CONTENT BEANS:
--------------
mvcContentNegotiationManager
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.format.support.FormattingConversionServiceFactoryBean
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.handler.MappedInterceptor
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
mainController
sillyService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
sillyService2
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor

Ahora mismo podríamos hacer uso de los beans desde cualquier parte de la aplicación, ya que están debidamente configurados, pero para seguir con el temario didáctico, vamos a crear un nuevo bean, cuya clase SillyMasterClass va a tratarse de un nuevo @Service que incluirá a los dos anteriores.

Lo interesante de esta clase, por no decir lo único interesante, es la anotación @Qualifier, que nos va a permitir informarle a Spring cual de los dos beans con misma clase es el que queremos inyectar en cada caso.

Si no especificamos el @Qualifier, Spring intentará resolver el nombre del bean con el propio nombre del atributo, en nuestro caso, sin @Qualifier seguiría compilando la aplicación, ya que nuestro bean id coincide con ambos nombres del atributo, pero si no fuera así, Spring en tiempo de compilación nos devolvería una BeanCreationException indicándonos que no sabe resolver cual de los dos beans debe inyectar.

@Service("sMService")
public class SillyMasterClass {

    @Autowired
    @Qualifier("sillyService")
    private SillyClass sillyService;
    @Autowired
    @Qualifier("sillyService2")
    private SillyClass sillyService2;

    public String getSillyOne(){

        return this.sillyService.getString();
    }

    public String getSillyTwo(){

        return this.sillyService2.getString();
    }
}

Ahora, desde nuestro JSP podemos hacer uso de “sMService” para acceder a los strings de los sillyServices.

${sMService.sillyOne} / ${sMService.sillyTwo}
Comparte esta entrada enShare on LinkedIn0Tweet about this on Twitter0Share on Facebook0Share on Google+0

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *