Inyección de Dependencia con Spring.Net
Spring.Net es uno de los frameworks más conocidos para implementar Inyección de Dependencia (también conocido como Inversión de Control -IoC). Otros que nos permiten hacer este trabajo son: PicoContainer, ObjectBuilder, Windsor Container.
Basicamente, qué queremos lograr? Fácil, crear nuestros objetos, sin importar quién me provea la implementación.
En vez de hacer esto:
(1) Cliente obj_cliente = new Cliente();
Podemos hacer esto:
(2) ICliente obj_cliente = (ICliente) AppContext.Instance.GetObject("Cliente");
Expliquemos, en (1) le estamos diciendo a obj_cliente quién va a crearlo: new Cliente(); Es decir, le estamos diciendo quien le va a proveer de la implementación, y nunca vamos a poder cambiar esto, a menos que lo hagamos y volvamos a compilar. En (2) es distinto, estamos pidiendo una implementación, pero no sabemos quien nos la va a dar. Solo sabemos que quién nos proveea la construcción, va a implementar la interfaz ICliente. AppContext es un wrapper que hice para crear un singleton del contexto de toda la aplicación (está en el codigo fuente que se puede descargar más abajo).
El lugar donde le decimos qué clase se va a encargar de la implementación, es en el app.config (en una de las tantas lineas para configurar Spring.Net):
<object name=?Cliente? type=?Entities.Cliente, Entities? singleton=?false?/>
En esta línea de código Entities.Cliente es la Clase que nos proveerá la implementación, y Entities es el assembly (que TIENE que estar en la carpeta de salida, donde está el .exe). También podemos ver cuan fácil es implementar un singleton de esta manera, solamente escribiendo singleton=”true” (ú obviandolo, es el valor por defecto), entonces no tenemos que hacerlo programaticamente.
Para el ejemplo lo que hice es organizar los proyectos de esta forma:
Lo que hariamos normalmente es referenciar Entities desde todas las partes del proyecto, en vez de esto, lo haremos con Entities.Contracts que contienen las interfaces, de modo que siempre programaremos contra las interfaces, nunca contra la implementación. Los proyectos no poseen relación de conocimiento con Entities, en ningún momento se lo referencia.
El tip del día: Hay que programar contra las interfaces.
Descargar codigo fuente [Proyecto hecho con SharpDevelop]
Donde más podemos utilizarlo ? En la capa de acceso a datos, podríamos persistir los objetos con db4o, y en otra implementación lo podríamos hacer usando NHibernate! Y esto lo lograríamos creando una interfaz IBaseRepository que tenga metodos como Guardar, Eliminar, Buscar y luego crear las implementaciones para cada uno de los providers por ejemplo BaseRepositoryDb4o y BaseRepositoryNH.
Espero que sirva!
19 Responses to “Inyección de Dependencia con Spring.Net”
RSS feed for comments on this post. TrackBack URL
Hola,
Cuando desarrollas con este tipo de fmks AOP que proporciona la reflexion pierdes la productividad que otorga el Intellisense del ensamblado que reflexionas?
Saludos.
Comment by Emilio Velardiez — 28 December 2006 @ 22:00
Cual es la mayor diferencia…
Estoy hablando nada mas y nada menos de Activator.CreateInstance(assembly, type);
o sea lo que veo es que Spring.net va a buscar el solo un objeto (¿Cualkiera?) que implemente ICliente y te lo tira… es algo un poco menos especifico que CreateInstance…
Recientemente estuve viendo el codigo de un plug in del Reflector de Lutz… y miraba como implementaba la conexion con la aplicacion host, es un tipico ejemplo ya que habia una linea: Reflector.ILoQueSea = this.plugInContext.GetLoQueSea();
(no era lo que sea, sino una de las tantas interfaces que expone Reflector, pero no es lo importante)
Dario, Podriamos usar este tipo de cosas para implementar un soporte de plugins? Hablando de plugins los nuevos aplication blocks traen un block para esto
Muy buen post!
Saludos
Comment by GLM — 29 December 2006 @ 1:53
Emilio: evidentemente al hacer una instanciacion de un objeto que no lo tiene referenciado, pierde el intellisense del objeto en si (porque la referencia no esta en el proyecto), pero Dario deberia tener la interface ICliente bien conocida (referenciada) en su proyecto, por lo que el trata en la aplicacion al objeto como un ICliente, y tiene intellisense de ICliente.
Podes pensarlo, si se te hace mas facil, como que ICliente es una clase base, y por lo tanto tenes acceso al intellisense. De hecho es valido usar una clase base para este tipo de escenarios, pero no estoy seguro si Spring.Net lo soporta.
Saludos
Comment by GLM — 29 December 2006 @ 2:03
Emilio, GLM respondió por mí. Al usar la interfaz ICliente, usas el intellisense sin problemas, que es un accidente de que se puedan ocupar los metodos, sino no tenés cómo trabajar con los métodos/properties/fields de Cliente.
Ahora bien, cual es la mayor diferencia entre Activator.CreateInstance(assembly,type) y lo que está haciendo Spring en el ejemplo ? CreateInstance es una función y Spring es un feroz framework
ahora… hablando solamente de la instanciación…ninguna. Convengamos que la inyección por Spring te dá mucho vuelo (es un framework no?), con solo poner singleton=true ténes el singletón cocinado. Aparte la instanciación se está realizando para un contexto, que en otra app, el contexto puede es otro y puede q cambiar la implementación…y esto se complica programandolo sin un framework q te ayude.
Con respecto a los plugins…esto es lo que se usa, no tenés otra (q yo conozca). Cambiarle las palabras/framework/helper hechos por nosotros, pero tarde o temprano tenes que usar estos principios.
Y como nombraba entre todos los containers que te permiten hacer IoC el ObjectBuilder es escrito por los muchachos de Patterns and Practices y es lo que se ocupa en los App Blocks (el link está al comienzo del post)
Que opinan ?
Comment by Dario Quintana — 29 December 2006 @ 6:14
Hola Dario,
Hasta donde yo se de POO el uso de Interfaces tienen que ver con la descripción de comportamientos, como ejemplos ISerializable o IDataBound. Creo que el uso que hacemos de “ICliente” se aproxima más a la de una clase abstracta y no a la de una Interfaz. No se que opináis al respecto?
Saludos.
Comment by Emilio Velardiez — 29 December 2006 @ 11:51
Es cierto, con interfaces hablamos sobre la descripción de comportamientos y es justamente los que necesitamos, por eso las usamos. Debemos saber exactamente que tiene que hacer alguien implemente una interfaz, sin importar como lo haga.
Tiene sus diferencias el hablar de clases Abstractas e Interfaces, aunque en algunos ambientes no importe que usemos.
El tema aquí es que nosotros estamos estableciendo un compromiso contractual entre las clases que quieran implementar ICliente, de modo que sí o sí debemos dar una implementación de todos los methods/properties en las clases que heredan/implementan de ICliente.
En una clase abstracta, no se dá esto, es decir, puedo en una clase derivada de AbstractCliente, no implementar un metodo ó una propiedad y optar hacerlo en una proxima derivada.
Otra cosa importante, es que al hablar de una clase abstracta (si bien no se puede instanciar) ya estamos hablando de una implementación, que puede ser mínima o no, y esto es justamente lo que estamos queriendo desacoplar, la implementación. Podría ser válido tener una clase AbstractCliente que implementa ICliente, y despues podríamos hacer que Cliente herede de AbstractCliente, pero en mi opinión no creo que justifique el esfuerzo, no creo que haya mucho que escribir en AbstractCliente.
Por cierto, muy buenos los comentarios!
Saludos
Comment by Dario Quintana — 29 December 2006 @ 17:31
Hola!
Muy interesante! Tenés de casualidad alguna aplicacion de muestra que utilice db4o (aunque sea muy básica)? De ser así te ofrezco subirla al wiki de db4o para que los interesados puedan tener un ejemplo hecho por vos.
Saludos!
German Viscuso
Comment by German Viscuso — 28 January 2007 @ 18:25
Estaba realizando una ejemplo entre NH y db4o pero no lo terminé
Tantito encuentre un tiempo lo termino y lo subo.
Saludos
Comment by Dario Quintana — 29 January 2007 @ 1:07
Ok, si lo terminas avisame por favor a la direccion german arroba db4o punto com
Saludos!
Comment by German Viscuso — 5 February 2007 @ 20:06
[...] por medio de un container de IoC. Para los que no sepan que es esto, pueden tener una introducción aquí con Spring.Net, o aquí utilizando [...]
Pingback by Mono.Sms y Windsor Container at Espacio de Dario Quintana — 8 August 2007 @ 12:15
[...] Usé NHibernate para el acceso a datos obviamente y Spring.Net para aplicar IoC y [...]
Pingback by 3 layer Example of NHibernate + Spring.Net + AOP at Espacio de Dario Quintana — 17 November 2007 @ 11:44
¡Hola Darío!
¡Excelente el post!
Saludos, Ricardo
Comment by Ricardo — 12 July 2008 @ 22:53
buenas darios, me parece excelente tu sitio..
yo soy nuevo en spring.net. estoy haciendo un motor de calculo el cual me funciona bien,mi problema es que si ago un cambio en la configuracion de mis objetos(modifico el valor de mis entities q recivira la clase) tngo q levantar sesion nuevamente. esto es asi o se puede modificar para q solo baste con guardar y no levantar sesion para q mi cambio se realize..
los objetos los guardo en el archivo Web.Config donde estan los datos de mi sesion.
saludos,espero me puedas ayudar..
gracias!!
Comment by francisco — 9 October 2008 @ 19:26
otra cosa q se me olvida, me podrias explicar lo q hacen los singleton,yo los tengo todos en false..
gracias Darìo
Comment by francisco — 9 October 2008 @ 19:29
Hola
¿Provee Spring.NET algo parecido a una plataforma OSGi?
Por razones de trabajo necesito, en .NET, las siguientes opciones:
OSGi
ORM
Rich Client Application
O algo por estilo.
Comment by Arian Fornaris — 23 November 2008 @ 13:46
ICliente obj_cliente = (ICliente) AppContext.Instance.GetObject(“Cliente”);
Como alternativa:
podemos poner cliente como una propiedad y lo inyectamos directamente a través del framework sin llamar al contenedor de manera directa…
//Lo inyectará directamente Spring, esto lo configuramos a través de un xml
private ICliente cliente;
public ICliente Cliente
{
get{return cliente;}
set{cliente = value;}
}
de esta manera no hacemos alusión en ningún momento al contenedor y nos desentendemos totalmente de su forma de creación
Comment by Martín Caballero — 1 November 2009 @ 14:17
Como propiedad de qué clase vas a poner a Cliente ? En algún momento, el contenedor va a aparecer querramos o no.
Comment by Dario Quintana — 2 November 2009 @ 11:41
Hola, buenas noches. Dario una pregunta, yo me encuentro actualmente desarrollando un proyecto donde necesito hacer uso de la inyeccion de dependencia.. MI proyecto es un sitio web y obviamente hago uso del web.config para realizar la inyeccion. Mi problema es el siguiente ( y voy a escribir el codigo para que me entiendas bien
)
Como podra ver, tendo un objeto que me permite gestionar apuestas y en este objeto inyecte 2 objetos mas , que son CategoriaDao y ApuestaDao. Estos 2 ultimos objetos son clases que tienen los metodos con los que manejo informacion de una base de datos de MySql. Y como podra ver, a cada uno de estos objetos le inyecte el AdoTemplate para poder tener acceso a los datos de la base de datos.
Tambien tengo una entidad APUESTA y una entidad CATEGORIA, donde la relacion es que en una categoria hay muchas apuestas.
EN mi entidad CATEGORIA tengo un atributo de tipo IList donde quiero traerme todas las apuestas de una categoria en especifico.. Pero quiero hacer esto usando la inyeccion que implemete en mi objeto GestionarApuestas.
No se como implementar esto.. por favor si seria tan amable de ayudarme
Comment by Daniel Bello — 19 December 2009 @ 22:02
ok el foro no me permite pegar el codigo.. no se por q.. pero bueno voy a xplicarme entoncs.. Tengo en el webconfig 3 objetos.. uno se llama GestionarApuestas el cual tiene inyectado 2 objetos que se llaman ApuestaDao y CategoriaDao y estos dos ultimos objetos tienen inyectado el AdoTemplate.
Comment by Daniel Bello — 19 December 2009 @ 22:06