Intentemos entenderlo a través de los dos ejemplos.
Ejemplo 1
En días anteriores, las aplicaciones utilizadas para generar solicitudes de comando para aceptar entradas de usuario una tras otra. Hoy en día, los marcos de UI crean una instancia de varios elementos de la interfaz de usuario, recorren varios eventos de esos elementos de la interfaz de usuario (como el mouse del mouse, el clic, etc.) y los programas de usuario / principal proporcionan enlaces (por ejemplo, los escuchas de eventos de la interfaz de usuario en Java) para escuchar esos eventos. Por lo tanto, el "control" principal del flujo de elementos de la interfaz de usuario se mueve del programa del usuario al marco de la interfaz de usuario. En días anteriores, estaba en el programa de usuario.
Ejemplo 2
Considere la clase CustomerProcessor
a continuación:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Si quiero que processCustomer()
sea independiente de cualquier implementación de getAllCusts()
, no solo la proporcionada por SqlCustRepo
, tendré que deshacerme de la línea: SqlCustRepo custRepo = new SqlCustRepo()
y reemplazarla con algo más genérico, capaz de aceptar diversos tipos de implementación, de manera que processCustomers()
simplemente funcionará para cualquier implementación provista.
El código anterior (instanciar la clase requerida SqlCustRepo
por la lógica del programa principal) es una forma tradicional y no logra este objetivo de desacoplar processCustomers()
de la implementación de getAllCusts()
. En la inversión de control, el contenedor crea una instancia de la clase de implementación requerida (según lo especificado por, digamos, configuración xml), lo inyecta en la lógica del programa principal que se enlaza según los ganchos especificados (por ejemplo, por @Autowired
anotación o getBean()
método en primavera marco).
Veamos cómo se puede hacer esto. Considera el siguiente código.
Config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="custRepo" class="JsonCustRepo" />
</beans>
CustRepo.java
interface ICustRepo
{ ... }
JsonCustRepo.java
class JsonCustRepo implements CustRepo
{ ... }
App.java
class App
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
}
}
También podemos tener
class GraphCustRepo implements ICustRepo { ... }
y
<bean id="custRepo" class="GraphCustRepo">
y no necesitaremos cambiar App.java.
Sobre el contenedor (que es el marco de Spring) tiene la responsabilidad de escanear un archivo xml, crear una instancia del bean de un tipo específico e inyectarlo en el programa del usuario. El programa de usuario no tiene control sobre qué clase se crea una instancia.
PS: IoC es un concepto genérico y se logra de muchas maneras. Los ejemplos anteriores lo consiguen mediante la inyección de dependencia.
Referencia: artículo de Martin Fowler .