Muestra las diferencias entre dos versiones de la página.
unidades:10_servidor:04_inyecciondependencias [2014/08/30 23:47] admin |
unidades:10_servidor:04_inyecciondependencias [2014/09/03 11:56] (actual) admin [La solución] |
||
---|---|---|---|
Línea 2: | Línea 2: | ||
La inyección de dependencias (en inglés Dependency Injection, DI) es un patrón de diseño sencillo de usar aunque quizás resulte algo muy novedoso para algunas personas. | La inyección de dependencias (en inglés Dependency Injection, DI) es un patrón de diseño sencillo de usar aunque quizás resulte algo muy novedoso para algunas personas. | ||
- | La DI intenta resolver el problema que hay en el código del ejemplo de JSON de hace 2 temas: | + | |
+ | ===== El problema ===== | ||
+ | La inyección de dependencias intenta resolver el problema que hay en el código del ejemplo de JSON de hace 2 temas: | ||
<sxh java;highlight: [5]> | <sxh java;highlight: [5]> | ||
Línea 31: | Línea 33: | ||
¿Cual es el problema que hay en ese código? ¡Si lo hicimos muy bien añadiendo el interfaz para abstraernos de saber nada de Jackson! Pero , ¿Seguro que no sabemos nada de Jackson? Si te fijas en la línea 5 verás que aparece la palabra "Jackson" en la clase ''JsonTransformerImplJackson''. | ¿Cual es el problema que hay en ese código? ¡Si lo hicimos muy bien añadiendo el interfaz para abstraernos de saber nada de Jackson! Pero , ¿Seguro que no sabemos nada de Jackson? Si te fijas en la línea 5 verás que aparece la palabra "Jackson" en la clase ''JsonTransformerImplJackson''. | ||
- | El problema es que tenemos dentro del código la implementación que usamos del interfaz y si usamos el interfaz para no saber nada sobre su implementación es un sin sentido que tengamos en el propio código una referencia a la implementación. | + | El problema es que tenemos dentro del código la implementación que usamos del interfaz y si usamos el interfaz para no saber nada sobre su implementación es un sin sentido que tengamos en el propio código una referencia a la implementación. Además is quisiéramos cambiar la implementación deberíamos ir por todo el código buscando donde se usa para cambiarlo. |
+ | |||
+ | ===== La solución ===== | ||
+ | La solución a todo ésto es la **Inyección de Dependencias** que evita que nuestro código tenga referencias a las implementaciones que usamos. | ||
+ | |||
+ | Vamos a modificar el controlador ''UsuarioController '' del tema anterior de forma que usemos ''JsonTransformer'': | ||
+ | |||
+ | <sxh java;highlight: [6];title:UsuarioController.java> | ||
+ | @Controller | ||
+ | public class UsuarioController { | ||
+ | |||
+ | @RequestMapping(value = {"/Usuario"}) | ||
+ | public void prueba(HttpServletRequest httpRequest, HttpServletResponse httpServletResponse) throws IOException { | ||
+ | JsonTransformer jsonTransformer=new JsonTransformerImplJackson(); | ||
+ | |||
+ | Usuario usuario=new Usuario("Alberto Tortosa","alberto_tortosa@gmail.com",91); | ||
+ | String jsonUsuario=jsonTransformer.toJson(usuario); | ||
+ | |||
+ | httpServletResponse.getWriter().println(jsonUsuario); | ||
+ | } | ||
+ | } | ||
+ | </sxh> | ||
+ | Vemos que ahora el controlador en vez de mostrar en la página web el texto "Hola mundo" retornara el JSON: | ||
+ | {"nombre":"Alberto Tortosa","email":"alberto_tortosa@gmail.com","edad":91} | ||
+ | |||
+ | Pero seguimos teniendo el mismo problema que antes. ¿Como lo resolvemos? Como ya tenemos configurado Spring en esta aplicación , nos va a resultar muy sencillo. Simplemente vamos a hacer unas pequeñas modificaciones: | ||
+ | * Decirle a Spring cual es la clase con la implementación de ''JsonTransformer'' | ||
+ | * Quitar la referencia a la implementación del controlador | ||
+ | * Indicar a Spring que inyecte la implementación en el controlador. | ||
+ | |||
+ | Vamos a modificar el fichero ''applicationContext.xml'' | ||
+ | <sxh xml;highlight: [12];title:applicationContext.xml> | ||
+ | <?xml version="1.0" encoding="UTF-8"?> | ||
+ | <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" | ||
+ | xsi:schemaLocation=" | ||
+ | http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd | ||
+ | http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd | ||
+ | "> | ||
+ | |||
+ | <context:annotation-config/> | ||
+ | |||
+ | <bean class="es.cursoangularjs.inyecciondependencias.json.JsonTransformerImplJackson" /> | ||
+ | |||
+ | </beans> | ||
+ | </sxh> | ||
+ | * Línea 12: Hemos añadido la clase ''es.cursoangularjs.inyecciondependencias.json.JsonTransformerImplJackson'' diciendo que ahora puede ser inyectada si solicitan una implementación del interfaz ''JsonTransformer'' | ||
+ | |||
+ | ¿Como sabe Spring que esa clase se debe inyectar si solicitan el interfaz ''JsonTransformer''? Muy sencillo porque mira la clase y ve que implementa ese interfaz. | ||
+ | |||
+ | Ahora debemos modificar el controlador para que le inyecten la clase definida en el fichero ''applicationContext.xml''. | ||
+ | |||
+ | <sxh java;title:UsuaroiController.java;highlight: [4,5]> | ||
+ | @Controller | ||
+ | public class UsuarioController { | ||
+ | |||
+ | @Autowired | ||
+ | private JsonTransformer jsonTransformer; | ||
+ | |||
+ | @RequestMapping(value = {"/Usuario"}) | ||
+ | public void prueba(HttpServletRequest httpRequest, HttpServletResponse httpServletResponse) throws IOException { | ||
+ | Usuario usuario=new Usuario("Alberto Tortosa","alberto_tortosa@gmail.com",91); | ||
+ | String jsonUsuario=jsonTransformer.toJson(usuario); | ||
+ | |||
+ | httpServletResponse.getWriter().println(jsonUsuario); | ||
+ | } | ||
+ | } | ||
+ | </sxh> | ||
+ | * Línea 5: Esta línea le dice a Spring que debe buscar una implementación del interfaz que hay a continuación y asignarle una instancia a la propiedad. | ||
+ | * Línea 6: Declaramos ahora la propiedad privada ''jsonTransformer'' pero no indicamos el objeto que lo implementa. Eso lo inyectará automáticamente Spring | ||
+ | |||
+ | Es decir que ahora la configuración sobre de implementaciones debemos usar está centralizada en el fichero ''applicationContext.xml'' y el resto de la aplicación gracias a la anotación ''@Autowired'' permite que se le inyecte la implementación que está definida en el fichero. Es decir que inyectar significa simplemente asignar un objeto a una propiedad pero sin que la clase a la que se le inyecta el objeto sepa de que clase es. | ||
+ | |||
+ | <note important> | ||
+ | Una cosa importante a tener en cuenta es que spring solo va a crear un única instancia de objeto a inyectar en toda la aplicación por lo que hay que tener cuidado con mantener un estado en el objeto o controlar el acceso de varias threads a la vez. | ||
+ | </note> | ||
+ | ===== Ejemplo ===== | ||
+ | El ejemplo de esta unidad es exactamente lo que acabamos de contar pero es un nuevo proyecto llamado "inyecciondependencias". | ||
+ | Lo único que debes recordar es que se han añadido también las librerías de Jackson y Spring. | ||
+ | |||
+ | <note> | ||
+ | Este ejemplo se encuentra en git en [[https://github.com/logongas/cursoangularjs/tree/master/inyecciondependencias]] | ||
+ | </note> | ||
+ |