Dominar la creación de dependencias propias en Spring Boot permite construir aplicaciones más flexibles y con una arquitectura limpia. En lugar de depender exclusivamente de estereotipos como @Service o @Component, es posible definir beans personalizados mediante la anotación @Configuration y el uso de @Bean, logrando un control total sobre las implementaciones que se inyectan en cada capa del proyecto.
¿Cómo crear un bean personalizado con interfaz e implementación?
El primer paso es organizar el proyecto correctamente. Se crea un paquete llamado bean donde se define una interfaz y su correspondiente implementación [0:22].
La interfaz MiBean declara un método void print().
La clase MiBeanImplement implementa esa interfaz y sobreescribe el método.
java
public interface MiBean {
void print();
}
java
public class MiBeanImplement implements MiBean {
@Override
public void print() {
System.out.println("Hola desde mi implementación propia del bean");
}
}
A continuación, se crea un paquete configuration donde se centraliza toda la configuración de beans propios. La clase MiConfigurationBean se anota con @Configuration para indicarle a Spring Boot que contiene definiciones adicionales de dependencias [1:22].
java
@Configuration
public class MiConfigurationBean {
@Bean
public MiBean beanOperation() {
return new MiBeanImplement();
}
}
La anotación @Configuration marca una clase como fuente de definiciones de beans. Dentro de ella, cada método anotado con @Bean devuelve una instancia que Spring registra en su contenedor de dependencias. Se utiliza la palabra reservada new para instanciar la implementación concreta.
¿Por qué cambiar implementaciones es una ventaja arquitectónica?
Uno de los mayores beneficios de este enfoque es la capacidad de intercambiar implementaciones sin modificar el código que consume la dependencia [3:10]. Al crear una segunda clase MiBean2Implement, basta con cambiar la instancia en el archivo de configuración:
java
@Bean
public MiBean beanOperation() {
return new MiBean2Implement();
}
En la clase FundamentosApplication, la inyección se realiza por constructor, y al ejecutar la aplicación el resultado cambia automáticamente sin tocar una sola línea del consumidor. Esto es lo que se conoce como inversión de control: el framework gestiona qué implementación concreta se entrega a cada componente.
¿Cómo inyectar una dependencia dentro de otra dependencia?
Spring Boot permite componer beans más complejos pasando una dependencia como parámetro de otra [4:25]. Para demostrarlo se crean dos nuevos elementos:
La interfaz MyOperation con un método int sum(int number).
La clase MyOperationImplement que suma uno al número recibido.
java
public class MyOperationImplement implements MyOperation {
@Override
public int sum(int number) {
return number + 1;
}
}
Después se define una interfaz MyBeanWithDependency y su implementación, que recibe MyOperation a través de su constructor [5:30]:
java
public class MyBeanWithDependencyImplement implements MyBeanWithDependency {
private final MyOperation myOperation;
publicMyBeanWithDependencyImplement(MyOperation myOperation){this.myOperation= myOperation;}@OverridepublicvoidprintWithDependency(){ int number =1;System.out.println(myOperation.sum(number));System.out.println("Hola desde la implementación de un bean con dependencia");}
}
¿Cómo se configura un bean que depende de otro bean?
En la clase de configuración, el método que registra el bean compuesto recibe la dependencia como parámetro. Spring resuelve automáticamente esa referencia desde su contenedor [6:45]:
java
@Bean
public MyBeanWithDependency beanOperationWithDependency(MyOperation myOperation) {
return new MyBeanWithDependencyImplement(myOperation);
}
Es fundamental que el tipo de retorno del método coincida con la interfaz, no con la clase concreta. Esto garantiza que Spring pueda resolver correctamente la inyección y evita errores de tipo en tiempo de compilación.
¿Qué resultado produce la inyección en cadena?
Al inyectar MyBeanWithDependency en FundamentosApplication y ejecutar el proyecto, la consola muestra el valor 2 —porque se envió 1 y la operación suma uno— seguido del mensaje de la implementación [8:12]. Esto confirma que la inyección de dependencias en cadena funciona correctamente: un bean consume otro bean sin acoplamiento directo entre clases concretas.
La sobreescritura de métodos mediante interfaces y la separación entre definición y configuración son pilares de este patrón. Cada pieza se puede probar, reemplazar o extender de forma independiente.
Si quieres practicar, crea tus propias dependencias con distintas implementaciones e inyéctalas en diferentes capas de la aplicación. Comparte tus resultados y dudas en la caja de comentarios.
No se si le pasó a otros en esta clase, pero aun prestando fuerte atención a las anteriores, cuando la vi por primera vez no me quedó claro por qué se tenía que crear el archivo MyConfigurationBean.java; después de devolverme varias veces a clases anteriores y leer detenidamente los aportes (incluso ver videos externos que algunos incluyeron en sus aportes) pude entenderlo un poco más, pero me molestó que no fuera claro en el hilo normal de las clases. Yo creo que es mejor explicar lo que está en esta clase como la base sobre la cual se implementa el patrón de Inversión de Control (lo cual hubiera hecho mucho más clara la clase anterior sobre el tema) y después como se puede hacer de forma diferente por medio de las anotaciones @component, @controller, @cepository y @service. Es una lástima que a veces, en función de hacer cursos prácticos para la gente, se pierda la posibilidad de abordar a profundidad conceptos claves para entender como desarrolladores qué es lo que de verdad hace el código que escribimos.
Estoy en total acuedo contigo
Totalmente de acuerdo, quede mareado así como lo explica en el video
Quizá sería más claro si en vez de crear una dependencia de tres clases con nombres totalmente random se hiciera un ejemplo real o al menos con algo de contexto.
Concuerdo, te perdés mucho con esto genérico sin sentido
Si quieres acceder rápido a la implementación de un método sin pasar por la interfaz, presiona Ctrl + Alt y luego clic sobre el método y te lleva a la implementación.
me parece que no es necesario el Alt?
Me parece que sin el Alt te envía a la interfaz
Un diagrama previo hubiera sido de ayuda en este video.
El video es bueno, pero apoyo la idea de Mauricio, creo ayudaria a quedar mas claro el el frujo y funcionamiento
Hola, este es un diagrama de secuencia el cual describe básicamente cómo los objetos e instancias intercambian mensajes en un orden determinado. Lo generé con el plugin gratuito SequenceDiagram for IntelliJ IDEA. En la parte superior se aprecian las clases e interfaces con colores distintos y en la parte inferior el flujo de los métodos. Me ayudo a comprender la idea de las dependencias. Saludos
MiConfigureichonBin! 🤪
Opereichon
jajaja
Esta clase me pareció de lo mas Horrible.
Sería de mucho provecho, antes de codificar los ejemplos, hacer uso de diagramas UML, para ver de una forma sencilla, cómo interactúan las clases, interfaces y demás. De resto, buen video 👌.
Estoy de acuerdo.
Este curso le faltan algunos detalles, los ejemplos deberían ser casos reales, los nombres de los archivos son muy random y si fuera algo real se asimilaria mejor la aplicación
Reto completado.
He utilizado un poco de programacion funcional para reforzar lo aprendido del curso de Platzi, usando Streams.
publicclassMyOwnOperationImplementimplementsMyOwnOperation{@OverridepublicList<Integer>generateRandomElements(int maxElement,int maxLimit){returnnewRandom().ints(0, maxElement).limit(maxLimit).boxed()// Regresa un IntStream.collect(Collectors.toList());}}
Bean con dependencia
MyOwnBeanWithDependency interface:
publicclassMyOwnBeanWithDependencyImplementimplementsMyOwnBeanWithDependency{privateMyOwnOperation myOwnOperation;publicMyOwnBeanWithDependencyImplement(MyOwnOperation myOwnOperation){this.myOwnOperation = myOwnOperation;}@OverridepublicvoiddisplayElements(){System.out.println("Llamamos a MyOwnOperationImplement para generar lista aleatoria");List<Integer> randNums =this.myOwnOperation.generateRandomElements(500,10); randNums.forEach(System.out::println);System.out.println("Hola desde mi implementacion de un bean con dependencia usando Streams y Listas");}
totalmente incomprensible este video, sin dar ejemplos y con nombres repetidos y redundantes, muchos tuvimos que repetirlo varias veces, no creo que sea la manera.
En la capa repository creo la clase Persona:
@RepositorypublicclassPersonaimplementsPersonaMethods{private int edad=32;privateString nombre="Mauricio";public int getEdad(){return edad;}publicvoidsetEdad(int edad){this.edad= edad;}publicStringgetNombre(){return nombre;}publicvoidsetNombre(String nombre){this.nombre= nombre;} @Overridepublicvoidsaludar(){System.out.println("Hola "+getNombre()+" tienes "+getEdad()+" años cumplidos.");}}
Al mismo nivel la interface PersonaMethods:
publicinterfacePersonaMethods{voidsaludar();}
En "FundamentosAplication" añado la línea en la parte superior:
El log del run arroja lo anterior realizado en el curso y:
"Hola Mauricio tienes 32 años cumplidos."
¿Cuál es la diferencia entre usar el @Qualifier o modificar la dependencia que se va a utilizar desde la clase MyConfigurationBean? Quiero decir, de todas maneras hay una parte del código donde se tiene que indicar qué implementación de la dependencia. ¿Alguien podría especificar mucho más estas ventajas por favor?
Mmm también me estaba preguntando lo mismo. Soy nueva con springboot pero aqui especulando un poco creo que una ventaja sería que, en caso de que por alguna razón estemos inyectando esa dependencia en varios lugares de nuestro código. Si en algún momento queremos cambiar de implementación lo podemos hacer directo en el bean en lugar de ir y cambiar manualmente todos los @Qualifier en toodo el código.
Además que se ve como más limpio...
Pero eso me deja preguntandome... para que hacer varias implementaciones si desde el bean solo voy a llamar una??? O puedo llamar difrentes implementaciones de la misma dependencia desde el bean.
No lo se jajaja muchas preguntas y pocas respuestas
a la pregunta de Pauzca, mmm creo que es para dejar listo por si acaso en un futuro queremos cambiar la implementacion
Reto Completado!!
Me costó mucho entender desde un inicio, he repetido más de 7 veces este video, al final si he comprendido pero requiere pausar y entender la lógica. Soy una persona muy visual y como consejo, ayuda mucho plantearlo visualmente y tener claro lo que hace cada clase. No hay que desanimarse si se puede !
que clase mas mala, no se entiende nada.
Creo que seria mucho mejor agregar un ejemplo mas realista que nombres tan poco recordables como MyBeanWithDependency
Cual seria la diferencia entre un @component a un @bean? los vi muy parecidos.
Hasta ahora estoy empezando en esto de Sprint, pero me imagino que es lo mismo que con las demás etiquetas, es decir, que se quiere implementar.
@Component es para algo muy general
@Repository para bases de datos
El @Bean lo veo como mi tag personalisable la cual no aplica para ninguno de los anteriores declaraciones si no para una implementación mas modular de mi lógica.
Como te digo es mi punto de vista, esperar a que la respondan.
Saludos
Hola estudiando un poco el tema encontre esto lo cual habla de las diferencias entre @Component y @Bean tambien me costo entenderlo al principio pero con esta tabla ya me quedaron mas claras las diferencias
HICE TODO IGUAL PERO ME ARROJA ESTE ERROR
APPLICATION FAILED TO START
Description:
Parameter 2 of constructor in com.fundamentos.springboot.fundamentos.FundamentosApplication required a bean of type 'com.fundamentos.springboot.fundamentos.bean.MyBeanWithDependency' that could not be found.
Action:
Consider defining a bean of type 'com.fundamentos.springboot.fundamentos.bean.MyBeanWithDependency' in your configuration.
Process finished with exit code 1
Hola
Te sugiero consultar dos páginas en donde se discute sobre este error y sus soluciones más a fondo. La primera es un hilo de StackOverflow y la siguiente otro foro de QStack en donde resuelven este problema.
Espero sea de utilidad.
Verifica de nuevo en el vídeo todas las anotaciones que se pusieron en el programa. A mí me ha surgido dos veces ese mismo error y cuando verifiqué otra vez me di cuenta de que me hacían falta anotaciones.
Tengo una inquietud.
Necesariamente se deben usar ocnsturctores?
o con la antación @Autowired, ya lo resolvemos??
O cuál es la recomendación con el uso de esta anotación?
Sin embargo como mencionas, también se puede resolver con @Autowired
Esta clase es confusa por los nombres que le da a las clases e interfaces, si no tenes buenos fundamentos de POO va a ser un calvario, de lo contrario no es tan dificil solo tienen que cambiar los nombres y listo.