viernes, 6 de diciembre de 2019

Dependency Injection Types [Spring]

Dependency Injection

Reference https://medium.com/@ilyailin7777/all-dependency-injection-types-spring-336da7baf51b

Types of Dependency Injection:

- Constructor.
- Setter.
- Field.
- lookup method.


1.- Constructor Injection (Immutable)


package com.bext
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
 
class ServiceA {
    void method() {
        System.out.println("ServiceA"); 
    }
}

class ServiceB {
    void method() {
        System.out.println("ServiceB");     
    }
}

class DependentService {
    private final ServiceA serviceA; 
    private final ServiceB serviceB;
    public DependentService(ServiceA serviceA, ServiceB serviceB) {
        this.serviceA = serviceA; 
        this.serviceB = serviceB; 
    }

    void method() {
        service1.method();         
        service2.method();     
    }

}

public class Main {
    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("spring.xml");
        ((DependentService) container.getBean("dependentService")).method();    }
}

<?xml version="1.0" encoding="UTF-8"?> 
<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.xsd">
 
    <bean id="serviceA" class="com.bext.ServiceA"/> 
    <bean id="serviceB" class="com.bext.ServiceB"/>
 
    <bean id="dependentService" class="com.bext.DependentService"> 
        <constructor-arg type="com.bext.ServiceA" ref="serviceA"/> 
        <constructor-arg type="com.bext.ServiceB" ref="serviceB"/> 
    </bean>
</beans>

Using Annotations

package com.bext;
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.ApplicationContext
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
 
@Service
class ServiceA {
    void method() {
        System.out.println("ServiceA"); 
    }
}

@Service
class ServiceB {
    void method() {
        System.out.println("ServiceB"); 
    }
}

@Service
class DependentService {
    private final ServiceA serviceA; 
    private final ServiceB serviceB;
     
    @Autowired
    public DependentService(ServiceA serviceA, ServiceB serviceB) {
        this.serviceA = serviceA; 
        this.serviceB = serviceB; 
    }

    void method() {
        serviceA.method(); 
        serviceB.method(); 
    }

}

public class Main {
    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("spring.xml");         
        ((DependentService) container.getBean("dependentService")).method(); 
   }
}

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.bext"/>

</beans>


  Advantages
      - Constructed objects are immutable and returned initialized.
      - More dependencies bigger the constructor.
      - can be combined with  setter injection of field injector, constructor parameters indicate
        required dependencies.
   Disadvantages
      - No possiblitiy to change object's dependencies later.
      - Higher change to have circular dependencies.

2.- Setter Injection ( mutability )

class DependentService {
    private ServiceA serviceA; 
    private ServiceB serviceB;
 
    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA; 
    }

    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB; 
    }

    void method() {
        serviceA.method();        serviceB.method(); 
    }
}


<?xml version="1.0" encoding="UTF-8"?> 
<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.xsd">
 
    <bean id="serviceA" class="com.bext.ServiceA"/> 
    <bean id="serviceB" class="com.bext.ServiceB"/>
 
    <bean id="dependentService" class="com.bext.DependentService"> 
       <property name="serviceA" ref="serviceA"/> 
       <property name="serviceB" ref="serviceB"/> 
    </bean>
</beans>

Using Annotations


@Service
class DependentService {
    private ServiceA serviceA; 
    private ServiceB serviceB;
     
    @Autowired
    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA; 
    }

    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB; 
    }

    void method() {
        serviceA.method(); 
        serviceB.method(); 
    }
}

with mandatory dependency (ServiceA final property)

@Service
class DependentService {
    private final ServiceA serviceA; 
    private ServiceB serviceB;
     
    @Autowired
    public void DependentService(ServiceA serviceA) {
        this.serviceA = serviceA; 
    }

    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB; 
    }

    void method() {
        serviceA.method(); 
        serviceB.method(); 
    }
}

  Advantages
   - Flexibility in dependency resolution or object reconfiguration, at any time.
   Disadvantages
     - Null checks are required.
     - Potentially more error prone and less secure than constructor injection. (by overriding dependencies).

3.- Field Injection

@Service
class DependentService {
    @Autowired
    private ServiceA serviceA;    
    @Autowired
    private ServiceB serviceB;
    void method() { 
     serviceA.method();        serviceB.method();    }
}

Spring Uses reflection to set these values

  Advantages
   - Easy to use, no constructors or setters required.
   - Can be easily combined with the constructor and/or setter approach.
  Disadvantages
   - Less control over object instantiation.
   - A number of dependencies can reach dozens until realize that something went wrong.
   - mutability.

4.- Lookup Method Injection

  Each time method is called, a new ServiceA is created, so the scope is prototype. the default is singleton. 

abstract class DependentService {
    private ServiceB serviceB; 
 
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB; 
    }

    void method() {
        createServiceA().method(); 
        serviceB.method(); 
    }

    protected abstract ServiceA createService1(); 
}

<?xml version="1.0" encoding="UTF-8"?> 
<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.xsd"> 
 
    <bean id="serviceA" class="com.bext.ServiceA" scope="prototype"/> 
    <bean id="serviceB" class="com.bext.ServiceB"/>
    <bean id="dependentService" class="com.bext.DependentService"> 
      <lookup-method name="createServiceA" bean="serviceA"/> 
      <property name="serviceB" ref="serviceB"/> 
    </bean>
</beans>

Using Annotations

@Service
@Scope(value = "prototype")
class ServiceA {
    void method() {
        System.out.println("ServiceA");     
    }
}

@Service
abstract class DependentService {
    private ServiceB serviceB;
     
    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB; 
    }

    void method() {
        createServiceA().method(); 
        serviceB.method();     
    }

    @Lookup
    protected abstract ServiceA createServiceA(); 
}

No hay comentarios:

Publicar un comentario