¿Para qué me sirve y qué resuelvo con Spring?

Hola chavos, pues esta vez el motivo de mi post es para preguntarles ¿cuáles son los apectos que favorecen el uso de Spring, cuál es la magia de este framework ?

Estoy iniciando con Spring y me gustaria que con lenguaje coloquial alguien me ayude a entender más

Porque he visto definiciones como:

Java components / classes should be as independent as possible of other Java classes. This increases the possibility to reuse these classes and to test them independently of other classes(Unit Testing). To decouple Java components from other Java components the dependency to a certain other class should get injected into them rather that the class itself creates / finds this object.

A class A has a dependency to class B if class uses class B as a variable.

If dependency injection is used then the class B is given to class A via

the constructor of the class A - this is then called construction injection

a setter - this is then called setter injection

The general concept between dependency injection is called Inversion of Control. A class should not configure itself but should be configured from outside.

A design based on independent classes / components increases the re-usability and possibility to test the software. For example if a class A expects a Dao (Data Access object) for receiving the data from a database you can easily create another test object which mocks the database connection and inject this object into A to test A without having an actual database connection.

A software design based on dependency injection is possible with standard Java.

Spring just add some simplifications in using dependency injection by providing a standard way of providing the configuration and by managing the reference to the created objects.

este otro:

The Spring Framework is a very comprehensive framework.

The fundamental functionality provided by the Spring Container is dependency injection. Spring provides a light-weight container, e.g. the Spring core container, for dependency injection (DI).

This container allows to inject required objects into other objects. This results in a design in which the Java class are not hard-coupled. The injection in Spring is either done via setter injection of via construction injection.

These classes which are managed by Spring must conform to the JavaBean standard.

In the context of Spring classes are also referred to as beans or as spring beans.

The Spring core container:

handles the configuration, generally based on annotations or on an XML file (XMLBeanFactory)

manages the selected Java classes via the BeanFactory

The core container uses the so-called bean factory to create new objects. New objects are generally created as Singletons if not specified differently.

Pero no me cae el 20, no me queda claro para que me sirve Spring que no se pueda hacer con alguna otra tecnologia(standard java,jsp,servlets,jsf,struts, etc)

He hecho los ejemplos que vienen en los tutoriales de Internet pero pues no me convence

Lo que si esta muy bien es Spring JDBC

De antemano gracias

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

IoC

Pues es que lo que dice ahí es lo que es Spring... pero bueno, explicado de otra forma... mmmmm... Spring se puede encargar de administrar los componentes de tu aplicación; es decir, de crearlos en el orden correcto, conectarlos entre sí, configurarlos, etc.

Imagínate que tienes un componente en tu aplicación de clase ImplComponenteA, que implementa la interfaz ComponenteA, que tiene un par de métodos que otros componentes invocan. Tiene también un par de propiedades, como por ejemplo un DataSource y un URL, un thread pool y una referencia a otro componente que implemente la interfaz ComponenteB. El componente se ve más o menos así:

public class ImplComponenteA implements ComponenteA {
  private ComponenteB b;
  private int hilos;
  private DataSource ds;
  private URL url;
  private ExecutorService tpool;

  //Los setters para todo eso
  public void setComponenteB(ComponenteB value) { b = value; }
  public void setHilos(int value) { hilos = value; }
  public void setDataSource(DataSource value) { ds = value; }
  public void setURL(URL value) { url = value; }

  //Y luego algunos metodos de la interfaz ComponenteA, etc.

  //Necesitas también un método de inicialización
  public void inicializa() {
    tpool = Executors.newFixedThreadPool(hilos);
  }
}

Ya desarrollaste el componente. Existe en aislamiento; compila perfectamente, tiene cara de que funciona bien. OK; ahora, cómo lo vas a probar? Tal vez se te ocurre hacer un programa más o menos así:

public class Programa {
  public static void main(String[] args) {
    ImplComponenteA a = new ImplComponenteA();
    DataSource ds = //todo el rollo para crear un DataSource
    URL url = new URL("http://blabla/");
    ImplComponenteB b = new ImplComponenteB();
    //algo más de código para configurar el componente b
    a.setDataSource(ds);
    a.setUrl(url);
    a.setHilos(1);
    a.setComponenteB(b);
    //Y ahora sí, después de todo ese rollo, a probar
    a.metodo1();
    a.metodo2();
    //Y luego algo para comprobar que todo salió bien, o lo revisas a mano en la base de datos, lo que sea.
  }
}

Ahora suponte que funciona perfecto. Luego qué? Cómo integras eso en tu aplicación? Empiezas con un buen de problemas de configuración; cómo puedo crear un DataSource? Ah, el contenedor lo puede manejar... sólo necesito obtener la referencia JNDI al mismo y pasarlo a mi componente. Y el número de hilos? Ah pues si hago un deployment descriptor y un montón de XML estándar de JEE y otro montón de XML propietario del contenedor que voy a usar, y le meto un montón de interfaces y dependencias de JEE a mi componente, puedo publicar el componente como un EJB, y administrarlo con el administrador del contenedor.

Y luego te dicen que no, eso es muy complicado. Mejor hazte un objeto configurador del componente. Entonces ya estás haciendo un buen de código que sólo sirve de pegamento, es decir, nomás es para alambrar el componente, conectarlo con los demás componentes de la aplicación y echarlo a andar. Debe haber una mejor manera.

Ahora con Spring: Utilizas un ApplicationContext, que es una abstracción de Spring con muchas variantes. Como su nombre lo indica, le da a tus componentes el contexto en el cual van a existir. Una variante común es un archivo de XML con la definición de los componentes y las referencias entre ellos (me voy ahorita por la manera más primitiva de usar Spring, sin auto-configuración ni nada de eso). Defines tus componentes más o menos así:

<bean id="compA" class="paquete.ImplComponenteA" init-method="inicializa">
  <property name="hilos" value="5" />
  <property name="url" value="http://blabla/" /><!-- Spring convertirá la cadena en URL -->
  <property name="componenteB" ref="compB" />
  <property name="dataSource=" ref="dataSource" />
</bean>

<bean id="compB" class="paquete.ImplComponenteB">
  <!-- la config de este bean, de manera similar -->
</bean>

<bean id="dataSource" class="algunDataSource">
  <!-- aqui su config -->
</bean>

El bean dataSource lo puedo crear usando un BasicDataSource de Apache Commons DBCP, o un DataSource normalito directo de algún driver de JDBC, o puede ser un proxy a un DataSource publicado en JNDI en un contenedor. No importa; la cosa es que ahora en vez de todo el código de pegamento, para tus pruebas puedes hacer algo así:

ClassPathXmlApplicationContext ctxt = new ClassPathXmlApplicationContext("beans.xml"); //el archivo XML con las definiciones
ComponenteA a = (ComponenteA)ctxt.getBean("compA");
a.metodo1();
a.metodo2();

Es decir, le pides los beans al applicationContext. El applicationContext analizará las dependencias entre beans, y entonces creará el DataSource y el compB, luego creará compA y le irá inyectando los valores indicados en el XML: el dataSource, el compB, el número de hilos, etc. Después invocará el método inicializa() en el compA y finalmente te lo entregará.

Por default, compA es un singleton; es decir si posteriormente hay más invocaciones al applicationContext de getBean("compA"), todas devolverán la misma instancia. De modo que puedes tener distintos componentes que no saben nada uno del otro y todos pueden hacer referencia al mismo compA. Esto es lo que se llama un contenedor ligero, porque es similar a lo que hace un contenedor JEE, con los EJB's, pero sin tanta complicación de implementar ciertas interfaces y hacer los deployment descriptors y que solamente los puedas probar en ese ambiente.

En caso que no sea evidente aún, este enfoque ofrece muchas ventajas:

- Ya no escribes código pegamento (donde solamente estás haciendo un montón de objetoA.setObjetoB(objetoB), etc).
- Al no haber código pegamento, se puede cambiar la configuración de una aplicación sin tener que recompilar
- Se pueden tener contextos distintos para pruebas, desarrollo y producción.

Este último punto es muy importante. Qué pasa si estás en un proyecto mediano a grande, y tú eres el encargado de desarrollar el ComponenteA, pero otra persona tiene que hacer el ComponenteB y va atrasada? No tienes por qué depender de su trabajo; si tú sabes lo que se supone que tiene que hacer ese componente, o simplemente es en cierta medida irrelevante al componenteA (sólo sabes que tienes que invocar un método y si no arroja excepción o si te devuelve un "OK" continúas y ya), entonces puedes hacer tu propio MockComponenteB que implemente la interfaz ComponenteB pero que no haga nada, o devuelva siempre OK, o que devuelva casi siempre OK excepto en casos controlados (cuando una bandera diga "arrojaError", pues que arroje un error). Y entonces usas ese MockComponenteB para probar tu ComponenteA. Al final cuando ya tengan listo el verdadero ComponenteB lo podrán probar nuevamente, pero tal vez eso sean pruebas más complicadas, en integración; tus pruebas unitarias las podrás realizar fácilmente.

Por cierto, Spring ofrece facilidades para pruebas unitarias y de integración, con jUnit o TestNG. Imagínate pruebas unitarias donde la misma clase de la prueba queda ya toda configurada (alambrada, conectada, etc) para cuando se ejecutan las pruebas. Algo así:

//Van un par de anotaciones aquí
public class PruebaComponenteA {
  @Resource private ComponenteA comp;

  @Test public void testMetodo1() {
    comp.metodo1();
  }

  @Test public void testMetodo2() {
    comp.metodo2();
  }
}

Mucho más cómodo, no? Spring en conjunto con jUnit (o TestNG) cargará un applicationContext que contenga un ComponenteA, lo inyectará a tu componente de pruebas y luego ya el framework de pruebas ejecutará tus métodos, te dará tu reporte, etc.

Algunas monerías adicionales que hace toda esta parte de applicationContext junto con otros módulos de Spring:

- Generar proxies a objetos publicados en JNDI, para que tú los veas como lo que deben ser (un DataSource por ejemplo, o un Session de JavaMail)
- Generar proxies a objetos RMI para que tengas la referencia local (no tienes que teclear una sola línea de código RMI).
- Crear objetos Properties a partir de archivos .properties y poder usarlos para inyectar sus valores en otros beans
- Encargarse de la creación y destrucción de los componentes (el applicationContext puede agregar ganchos a la JVM para ser notificado cuando la aplicación termina y poder invocar los métodos de shutdown a los componentes que lo requieran).
- Manejar varios archivos de configuración, no tiene que ser uno solo, y poder importar uno en otro, o bien crear el applicationContext indicándole todos los archivos a cargar (de modo que no dependa uno de otro).
- Componentes de conveniencia para poder interactuar con distintos frameworks como JSF, JSP's, Hibernate, iBatis, etc.
- Crear proxies dinámicos que envuelvan a tus beans, para poder manejar métodos de manera transaccional o con algún otro interceptor estilo AOP

Bueno podría seguirle pero creo que ya es bastante. Espero que esto te dé una mejor idea de todo lo que Spring puede hacer por ti.

Lo malo de las cosas útiles que hacen mucho

Pues Spring a groso modo es un framework modular que hace muchas cosas y que muchas personas usan una parte minúscula del mismo y ya por eso dicen: "Spring sirve para...", pero en sí es un framework con varios módulos que permiten -según esto- hacer la vida más simple para el programador.

Viene con un módulo para Dependency Injection, otro para Aspect Oriented Programming, creo que incluye una utilería para usar JDBC con menos dolor, en fin, tiene tantas cosas que es difícil decir en una oración que es Spring.

El ejemplo de @ezamudio, está chido, pero ya cuando tienes algo de idea; de entrada a Spring esto puede parecer más un: "utaaa, ahora voy a tener que teclear más de lo que ya tecleo, bendito Spring".

Otro enorme problema que veo es el síndrome que se sufría con Java y JavaScript (y que algunos lo siguen sufriendo). Mucha gente dice que Spring es sólo el framework Spring MVC siendo que Spring MVC es un módulo (si estoy mal favor de corregir) de Spring.

Tendrías que revisar que funciones específicas necesitas o la razón por la que quieres aprender Spring (quizás sólo quieres aprender a usar la parte de DI o de AOP...o simplemente sólo quieres aprender Spring MVC). De esa forma la ayuda puede ser más específica. Aunque aclaro, a esto del Spring le dejé de hacer hace ya un tiempo.