tutorial example java spring

java - example - primavera e interfaces



spring security oauth2 (8)

Leí por todas partes cómo Spring te anima a usar interfaces en tu código. Yo no lo veo No hay ninguna noción de interfaz en su configuración Spring Xml. ¿Qué parte de Spring realmente lo anima a usar interfaces (que no sean los documentos)?


Probablemente quiera intentar usarlo para que pueda ver esto mejor, puede que no sea claro en los documentos cómo Spring alienta el uso de la interfaz.

Aquí hay un par de ejemplos:

  1. Digamos que está escribiendo una clase que necesita leer de un recurso (por ejemplo, un archivo) al que se puede hacer referencia de varias maneras (por ejemplo, en classpath, ruta de archivo absoluta, como URL, etc.). org.springframework.core.io.Resource definir una org.springframework.core.io.Resource (interfaz) en su clase. Luego, en su archivo de configuración de Spring, simplemente seleccione la clase de implementación real (por ejemplo, org.springframework.core.io.ClassPathResource , org.springframework.core.io.FileSystemResource , org.springframework.core.io.UrlResource , etc.). Spring funciona básicamente como una fábrica extremadamente genérica.

  2. Si desea aprovechar la integración de AOP de Spring (para agregar interceptores de transacción, por ejemplo), necesitará definir interfaces. Usted define los puntos de interceptación en su archivo de configuración de Spring, y Spring genera un proxy para usted, basado en su interfaz.

Estos son ejemplos con los que personalmente tengo experiencia. Estoy seguro de que hay mucho más por ahí.


La mayoría de las respuestas aquí son alguna forma de "Usted puede cambiar implementaciones fácilmente", pero lo que creo que no pueden responder es el por qué? parte. A eso creo que la respuesta es casi definitivamente comprobable. Independientemente de si usa Spring o cualquier otro marco de IOC, el uso de Dependency Injection hace que su código sea más fácil de probar. En el caso de decir un escritor en lugar de un PrinterWriter, puede simular la interfaz Writer en una prueba unitaria y asegurarse de que su código lo llame de la manera que esperaba. Si depende directamente de la implementación de la clase, su única opción es dirigirse a la impresora y verificarla, lo cual no es muy automático. Además, si depende del resultado de una llamada a una clase, no poder simular puede evitar que pueda alcanzar todas las rutas de código en su prueba, reduciendo así su calidad (potencialmente) En pocas palabras, debe desacoplar el objeto creación de gráfico desde la lógica de la aplicación. Hacerlo hace que tu código sea más fácil de probar.


Spring no lo forzará a usar interfaces en ninguna parte, es solo una buena práctica. Si tiene un bean que tiene algunas propiedades que son interfaces en lugar de clases concretas, puede simplemente cambiar algunos objetos con maquetas que implementan la misma interfaz, lo cual es útil para ciertos casos de prueba.

Si utiliza, por ejemplo, las clases de soporte de Hibernate, puede definir una interfaz para su DAO y luego implementarla por separado; la ventaja de tener la interfaz es que podrá configurarla utilizando los interceptores Spring, lo que le permitirá simplificar su código; no tendrá que escribir ningún código en HibernateExceptions y cerrar la sesión en un segmento finally, y tampoco tendrá que definir ninguna transacción de forma programática, simplemente configure todo eso de manera declarativa con Spring.

Cuando estás escribiendo aplicaciones rápidas y sucias, puedes implementar DAO simple usando JDBC o algún framework simple que no terminarás usando en la versión final; podrá cambiar fácilmente esos componentes si implementan algunas interfaces comunes.


es fácil generar proxies a partir de las interfaces.

si miras cualquier aplicación de primavera, verás las interfaces de servicio y persistencia. haciendo que la expresión primaveral fomente el uso de interfaces. no se vuelve más explícito que eso.


Cuando define una interfaz para sus clases, ayuda con la inyección de dependencia. Los archivos de configuración de Spring no tienen nada sobre las interfaces en sí mismos; solo debe poner el nombre de la clase.

Pero si desea inyectar otra clase que ofrezca una funcionalidad "equivalente", usar una interfaz realmente ayuda.

Por ejemplo, diciendo que tienes una clase que analiza el contenido de un sitio web y lo estás inyectando con Spring. Si las clases en las que lo está inyectando saben cuál es la clase real, entonces para cambiarla tendrá que cambiar una gran cantidad de código para usar una clase concreta diferente. Pero si creó una interfaz Analyzer , podría fácilmente inyectar su DefaultAnalyzer original como podría hacer con un DummyAnalyzer o incluso con otro que haga esencialmente lo mismo, como un PageByPageAnalyzer o cualquier otra cosa. Para usar uno de ellos, solo tiene que cambiar el nombre de clase que está inyectando en sus archivos de configuración de Spring, en lugar de ir a través de su código cambiando las clases.

Me tomó alrededor de un proyecto y medio antes de que realmente empezara a ver la utilidad. Como la mayoría de las cosas (en los lenguajes de empresa) que terminan siendo útiles, al principio parece una adición inútil de trabajo, hasta que su proyecto comienza a crecer y luego descubre cuánto tiempo ahorró haciendo un poco más de trabajo por adelantado.


Nadie ha mencionado aún que en muchas ocasiones no será necesario crear una interfaz para que la clase implementadora se pueda cambiar rápidamente porque simplemente no habrá más de una clase implementadora.

Cuando las interfaces se crean sin necesidad, las clases se crearán por pares (interfaz más implementación), agregando interfaces repetitivas innecesarias y creando posibles confusiones de dependencia porque, en los archivos de configuración XML, los componentes serán a veces referenciados por su interfaz y algunas veces por su implementación, con no hay consecuencias en el tiempo de ejecución, pero es incoherente con respecto a las convenciones del código.


Si no utiliza interfaces, corre el riesgo de una falla de autoenvío : en algún momento Spring crea una clase Proxy para un Bean. Esta clase Proxy no es una clase secundaria de la implementación del servicio, pero implementa nuevamente todas sus interfaces. Spring intentará autoaumentar instancias de este Bean, sin embargo esta clase Proxy es incompatible con la clase Bean. Por lo tanto, declarar un campo con la clase Bean puede generar excepciones de "asignación insegura de campos".

No se puede saber con certeza cuándo Spring está yendo a Proxy a service (ni debería hacerlo), así que para protegerse contra esas sorpresas, lo mejor es declarar una interfaz y usar esta interfaz al declarar campos autocableados.


El Principio de Inversión de Dependencia explica esto bien. En particular, figura 4.

A. Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de las abstracciones.

B. La abstracción no debería depender de los detalles. Los detalles deben depender de las abstracciones.

Traduciendo los ejemplos del enlace de arriba a java:

public class Copy { private Keyboard keyboard = new Keyboard(); // concrete dependency private Printer printer = new Printer(); // concrete dependency public void copy() { for (int c = keyboard.read(); c != KeyBoard.EOF) { printer.print(c); } } }

Ahora con inversión de dependencia:

public class Copy { private Reader reader; // any dependency satisfying the reader interface will work private Writer writer; // any dependency satisfying the writer interface will work public void copy() { for (int c = reader.read(); c != Reader.EOF) { writer.write(c); } } public Copy(Reader reader, Writer writer) { this.reader = reader; this.writer = writer; } }

Now Copy admite más que simplemente copiar de un teclado a una impresora.

Es capaz de copiar desde cualquier Reader a cualquier Writer sin requerir ninguna modificación a su código.

Y ahora con Spring:

<bean id="copy" class="Copy"> <constructor-arg ref="reader" /> <constructor-arg ref="writer" /> </bean> <bean id="reader" class="KeyboardReader" /> <bean id="writer" class="PrinterWriter" />

o quizás:

<bean id="reader" class="RemoteDeviceReader" /> <bean id="writer" class="DatabaseWriter" />