Friday, October 28, 2022

Spring - Inversion Of Control [IOC]

1. What is Inversion Of Control?

  • In general, in enterprise applications, if we need any service in our application then we have to put a request to the service provider, where the service provider has to create the required service and then the service provider has to send that service to the respective application.
  • In enterprise applications, Inversion Of Control is a design pattern or a design principle, it will make the service provider identify the required services of the enterprise applications and it will make the service provider to create and inject the required services into the application without expecting any request from the application.
  • IOC is available in the following forms.
    • 1. Dependency Lookup 
    • 2. Dependency Injection 

2. Dependency Lookup

  • In Dependency Lookup, Service Provider will create the services and maintain those services either in the registry Software or in the containers, where we have to perform lookup operations in order to get the required services.
  • There are two ways to get achieve Dependency lookup. 

    • 1. Dependency Pull
    • 2. Contextualized Dependency Lookup

1. Dependency Pull:

  • In Dependency Pull, Service Provider will create services and it will keep that services in any registry software, where we have to perform a lookup operation in order to get the required services, that is, pull the required services from registry software.

  • Example 1 : 
    • When we start application Servers like Weblogic, JBOSS, Websphere, and Glassfish, automatically, Application Servers will create Datasource object and Application Servers will keep that Datasource object in JNDI Server as per the server settings which we made in the application Server. In this context, we have to perform a lookup(--) operation over the JNDI server on the basis of the logical name in order to get the required Datasource object.

  • Example 2:
    • IN RMI Applications, User defined Registry Application will create Remote object and it will keep that Remote object in RMIRegistry with a particular logical name , here to get the required Remote object in Client Application we have to perform lookup operation over RMIRegistry on the basis of the logical name.

2. Contextualized Dependency Lookup

  • In this mechanism, Service Provider will create the services and manage services , in this context, we have to perform lookup operation inorder to get the required services from Service Provider.
  • Example: 
    • In general, in web applications, when we start application Server then container will recognize all the web applications and container will deploy all the web applications into the server, when web applications are deployed in server , container will create ServletContext object automatically and Container will manage ServletContext object.

    • in this context , to get ServletContext object we have to use getServletContext() method from GenericServlet directly with out using any reference variable, from ServletConfig object reference and from ServletRequest object reference, that is, performing lookup operation in Container to get ServletContext object.

3. Dependency Injection

  • In this mechanism, Service Provider will create the services and inject the required services into the application directly without performing lookup operations and without getting requests from the client.

  • Example 
    • In web applications, when we submit request to a particular Servlet , Container will execute the requested Servlet by performing the Servlet life cycle actions like Servlet Loading, Servlet Instantiation, Servlet Initialization , Request Processing and Servlet Deinstantiation. 

    • In Servlet initialization phase, container will create ServletConfig object and Container will inject ServletConfig object to the Servlet program through init(--) method, in Request Processing phase, Container has to create request and response objects and Container has to inject request and response objects to the Servlet program through service() method.

public class MyServlet extends HttpServlet{
    ServletConfig config;
    
    public void init(ServletConfig config)throws ServletException{ 
        this.config=config;
    }
    public void service(ServletRequest request, ServletResponse response) 
        throws ServletException, IOException{
            ----
    }
}


There are two ways to achieve dependency injection. 

  1. Constructor Dependency Injection
  2. Setter Method Dependency Injection

1. Constructor Dependency Injection

  • If we inject dependent values to the Bean object through Constructor then this type of Dependency Injection is called as "Constructor Dependency Injection".
  • If we want to use constructor dependency injection in Spring applications, first we have to declare the respective parameterized constructor in the corresponding bean class then we have to declare the constructor arguments in the spring configuration file by using the following tags.

<beans>
    <bean ..... >
        <constructor-arg value="--"/> <constructor-arg> value </constructor-arg>
    </bean>
    ---- 
</beans>

Example:

Course.java

package com.cloud.beans;
public class Course { 
    private String cid;
    private String cname; 
    private int ccost;

    public Course(String cid, String cname, int ccost){ 
        this.cid=cid;
        this.cname=cname;
        this.ccost=ccost; 
    }

    public void getCourseDetails(){ 
        System.out.println("Course Details"); 
        System.out.println("-------------------"); 
        System.out.println("Course Id :"+cid); 
        System.out.println("Course Name :"+cname); 
        System.out.println("Course Cost :"+ccost);
    } 
}

applicationContext.xml

 <beans>
    <bean id="crs" class="com.cloud.beans.Course">
    <constructor-arg value="C-111"/> <constructor-arg value="JAVA"/> 
    <constructor-arg value="5000"/>
    </bean> 
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.Course;
public class Test {
    public static void main(String[] args)throws Exception {
        ApplicationContext context=
            new ClassPathXmlApplicationContext("applicationContext.xml"); 

        Course course=(Course)context.getBean("crs"); 
        course.getCourseDetails();
    }
}

2. Setter Method Dependency Injection

  • If we inject dependent values to the Bean through setXXX() methods then it is called a "Setter Method Dependency Injection".
  • To inject primive values and String value to the bean object then we have to use "value" attributes in <property> or <constructor-arg> tags in beans configuration file, but, If we want to inject User defined data types , that is, Object reference values then we have to use "ref" attribute in <property> tag or in <constructor-arg> tag.

Example:

Account.java

package com.cloud.beans;
public class Account { 
    private String accNo;
    private String accName; 
    private String accType; 
    private long balance;

    setXXX()
    getXXX() 
}

Employee.java

package com.cloud.beans;
public class Employee { 
    private String eid;
    private String ename; 
    private float esal; 
    private String eaddr; 
    private Account acc;

    setXXX() 
    getXXX()

    public void getEmployeeDetails() {
        System.out.println("Employee Details"); 
        System.out.println("-------------------"); 
        System.out.println("Employee Id :"+eid); 
        System.out.println("Employee Name :"+ename); 
        System.out.println("Employee Salary :"+esal); 
        System.out.println("Employee Address:"+eaddr); 
        
        System.out.println("Account Details"); 
        System.out.println("-------------------"); 
        System.out.println("Account Number :"+acc.getAccNo()); 
        System.out.println("Account Name :"+acc.getAccName()); 
        System.out.println("Account Type :"+acc.getAccType()); 
        System.out.println("Account Balance:"+acc.getBalance());

    } 
}

applicationContext.xml

<beans>
    <bean id="acc" class="com.cloud.beans.Account">
        <property name="accNo" value="abc123"/> 
        <property name="accName" value="cloud"/>
        <property name="accType" value="Savings"/>
        <property name="balance" value="25000"/> 
    </bean>
    <bean id="emp" class="com.cloud.beans.Employee"> 
        <property name="eid" value="E-111" />
        <property name="ename" value="cloud"/> 
        <property name="esal" value="50000"/> 
        <property name="eaddr" value="Hyd"/>
        <property name="acc" ref="acc"/> 
    </bean>
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.Employee;

public class Test {
    public static void main(String[] args)throws Exception {
        ApplicationContext context=
            new ClassPathXmlApplicationContext("applicationContext.xml");
        Employee emp=(Employee)context.getBean("emp"); 
        emp.getEmployeeDetails();
    }
}
4.Different Types of Elements Injection
4.1. User-defined data types elements injection. 
  • In Spring applications, if we want to inject User defined data types then we have to use either "ref" attribute in <property> and <constructor-arg> tags or we have to use <ref> nested tag under <property> and <constructor-arg> tags

Example:

  <beans>
  <bean id="--" class="--"> 
    <property name="--" ref="--"/>
    <ref bean="--"/> </property>
  </bean> 
</beans>

4.2.List types injection

  • In spring applications, if we want to inject List of elements in beans then we have to declare the corresponding property as java.util.List and we have to provide values in configuration file by using <list> tag in <property> tag or in <constructor-arg> tag.

Example:

<beans>
  <bean id="---" class="--"> 
    <property name="--">
      <list> 
        <value>value1</value> 
        <value>value2</value>
          ----
          ---- 
      </list>
    </property> 
  </bean>
</beans>
4.3 Set types injection
  • In Spring applications, if we want to inject Set of elements in Bean object then we have to declare the corresponding property as java.util.Set and we have to provide values in configuration file by using <set> tag under <property> tag or <constructor-arg> tag.

Example:

 <beans>
  <bean id="---" class="--">
    <property name="--"> 
      <set>
        <value>value1</value> 
        <value>value2</value>
        ----
       ---- 
      </set>
    </property> 
  </bean>
</beans>
4.4 Map Types Injection
  • In Spring applications, if we want to inject Map of elements in Bean object then we have to declare the corresponding property as java.util.Map and we have to provide Key-Value pairs in configuration file by using <map> and <entry> tags under <property> tag or <constructor-arg> tag.

Example:

<beans>
  <bean id="--" class="--"> 
  <property name="--">
    <map>
      <entry key="key1" value="value1"/> 
      <entry key="key2" value="value2"/> ----
    </map> 
  </property>
  </bean> 
</beans>
4.5 Properties types Injection
  • In Spring applications, if we want to inject Properties of elements in Bean object then we have to declare the corresponding property as java.util.Properties and we have to provide Key-Value pairs in the configuration file by using <props> and <prop> tags under <property> tag or <constructor-arg> tag.

Example:

  <beans>
  <bean id="--" class="--"> 
  <property name="--">
    <props>
      <prop key="key1"> value1</prop> 
      <prop key="key2"> value2</prop> 
      ----
    </props> 
  </property>
  </bean> 
</beans>
Example:
Student.java
package com.cloud.beans;
import java.util.List; 
import java.util.Map; 
import java.util.Properties; 
import java.util.Set;
public class Student { 
   private String sid;
   private String sname;
   private Address saddr;
   private List<String> squal;
   private Set<String> scourses;
   private Map<String, String> scourses_And_Faculty;
   private Properties scourse_And_Cost;

   setXXX() 
   getXXX()

   public void getStudentDeails(){

      System.out.println("Student Details");
      System.out.println("-------------------");
      System.out.println("Student Id :"+sid);
      System.out.println("Student Name :"+sname); 
      System.out.println("Student Address :"+saddr); 
      System.out.println("Student Qualifications :"+squal); 
      System.out.println("Student Courses :"+scourses); 
      System.out.println("Student Courses And Faculty :"+scourses_And_Faculty);
      System.out.println("Student Courses And Cost"+scourse_And_Cost) 
   }

}
Address.java
package com.cloud.beans; 
public class Address {
       private String pno; 
       private String street; 
       private String city; 
       private String country;

       setXXX() 
       getXXX()

       public String toString(){
              return pno+","+street+","+city+","+country;
       }
}
applicationContext.xml
<beans>
  <bean id="addr" class="com.cloud.beans.Address">
    <property name="pno" value="202"/> 
    <property name="street" value="M G Road"/> 
    <property name="city" value="Banglore"/> 
    <property name="country" value="India"/>
  </bean>
  <bean id="std" class="com.cloud.beans.Student">
    <property name="sid" value="S-111"/> 
    <property name="sname" value="cloud"/> 
    <property name="saddr">
      <ref bean="addr"/> 
    </property>
    <property name="squal"> 
      <list>
       <value>BTech</value> 
       <value>MTech</value> 
       <value>PHD</value>
      </list> 
    </property>

    <property name="scourses">
      <set>
        <value>Core Java</value> 
        <value>Adv Java</value> 
        <value>Spring</value> 
        <value>Hibernate</value> 
        <value>WebServices</value>
      </set> 
    </property>

    <property name="scourses_And_Faculty"> 
      <map>
        <entry key="Core Java" value="Ratan"/> 
        <entry key="Adv Java" value="cloud"/> 
        <entry key="Spring" value="Sriman"/> 
        <entry key="Hibernate" value="Naveen"/> 
        <entry key="Webservices" value="Naidu"/>
      </map> 
    </property>

    <property name="scourse_And_Cost"> 
      <props>
        <prop key="Core Java">1500</prop> 
        <prop key="Adv Java">2000</prop> 
        <prop key="Spring">3000</prop> 
        <prop key="Hibernate">3000</prop> 
        <prop key="Webservices">3000</prop>
      </props> 
    </property>
  </bean>
</beans>
Test.java
package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.Student;

public class Test {
  public static void main(String[] args)throws Exception {
    ApplicationContext context=
      new ClassPathXmlApplicationContext("applicationContext.xml");
    Student std=(Student)context.getBean("std");  
    std.getStudentDeails();
  }
}


4.6 Circular Dependency Injection:

  • In Spring applications, if more than one bean object is depending on each other through constructor dependency injection then it is called Circular Dependency Injection, which is not supported by Spring framework, it is able to rise an exception like 
    • " org.spring framework.beans.factory.BeanCurrentlyInCreationException"

Example:

Student.java

 package com.cloud.beans;
  public class Student { 
    Branch branch;
  
    public Student(Branch branch) { 
      this.branch=branch;
    }

    public String getStudentName(){
        return "cloud"; 
    }
}

Branch.java

package com.cloud.beans;
public class Branch { 
  Student student;
  public Branch(Student student) { 
    this.student=student;
  }
  public String getBranchName(){
    return "S R Nagar"; 
  }
}

appliocationContext.xml

<beans>
  <bean id="student" class="com.cloud.beans.Student"> 
  <constructor-arg ref="branch"/>
  </bean>
  <bean id="branch" class="com.cloud.beans.Branch">
    <constructor-arg ref="student"/> 
  </bean>
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.Branch; import com.cloud.beans.Student;
public class Test {
  public static void main(String[] args)throws Exception { 
    ApplicationContext context=
      new ClassPathXmlApplicationContext("applicationContext.xml"); 

    Student std=(Student)context.getBean("student"); 
    System.out.println(std.getStudentName());
    
    Branch branch=(Branch)context.getBean("branch"); 
    System.out.println(branch.getBranchName());
  }

}

  • In Spring applications, if we want to resolve Circular Dependency Injection then we have to use Setter Method dependency Injection instead of Constructor Dependency Injection. 

Student.java

public class Student {
  Branch branch;
  setXXX() 
  getXXX()
}

Branch.java

package com.cloud.beans;
public class Branch { 
  Student student;
  setXXX() 
  getXXX()
}

applicationContext.xml

<beans>
  <bean id="student" class="com.cloud.beans.Student">
    <property name="branch" ref="branch"/> 
  </bean>
  
  <bean id="branch" class="com.cloud.beans.Branch"> 
    <property name="student" ref="student"/>
  </bean> 
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.Branch; import com.cloud.beans.Student;
public class Test {
  public static void main(String[] args)throws Exception { 
    ApplicationContext context=
      new ClassPathXmlApplicationContext("applicationContext.xml"); 
    Student std=(Student)context.getBean("student"); 
    System.out.println(std.getStudentName());
  
    Branch branch=(Branch)context.getBean("branch"); 
    System.out.println(branch.getBranchName());
  }
}

Question

In Spring applications, if we provide both Setter method dependency injection and Constructor dependency injection to a single bean then what will happen to Spring Application?

  • If we provide both Constructor dependency injection and Setter method dependency injection to a single bean then IOC Container will perform constructor dependency injection first at the time of creating Bean object , after that, IOC Container will perform Setter method dependency injection, that is, Constructor Dependency Injection provided values are overridden with setter method dependency injection provided values, finally, Bean object is able to manage Setter method dependency Injection provided values.

Example:

Student.java

package com.cloud.beans; 
public class Student {
  private String sid;
  private String sname;
  private String saddr;

  public Student(String sid, String sname, String saddr){
    this.sid=sid;
    this.sname=sname;
    this.saddr=saddr; 
    System.out.println("Student(---)-Constructor");
  }

  setXXX() 
  getXXX()
  
  public void getStudentDetails(){
    System.out.println("Student Details"); 
    System.out.println("-------------------"); 
    System.out.println("Student Id :"+sid); 
    System.out.println("Student Name :"+sname);
    System.out.println("Student Address :"+saddr);
  }
}

applicationContext.xml

 <beans>
  <bean id="std" class="com.cloud.beans.Student"> 
    <constructor-arg index="0" value="S-111"/> 
    <constructor-arg index="1" value="AAA"/> 
    <constructor-arg index="2" value="Hyd"/>

    <property name="sid" value="S-222"/> 
    <property name="sname" value="BBB"/> 
    <property name="saddr" value="Sec"/>
  </bean> 
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.Student;

public class Test {
  public static void main(String[] args) {
    ApplicationContext context=
      new ClassPathXmlApplicationContext("applicationContext.xml");
    
    Student std=(Student)context.getBean("std");
    std.getStudentDetails();
  }
}

Question

What are the differences between Constructor Dependency Injection and Setter Method Dependency Injection?

  • In Constructor dependency injection, dependent values injected through a particular constructor.
  • In Setter method dependency injection, dependent values are injected through properties respective setXXX() methods.
  • In Constructor Dependency Injection readability is not good , because, in Constructor dependency injection we are unable to identify to which property we are injecting dependent values.
  • In setter method Dependency injection Readability is very good, because, in Setter method Dependency injection we are able to identify that to property we are able to inject the dependent values.
  • In Constructor Dependency injection , dependency injection is possible when all dependent objects are getting ready, if dependent objects are not ready then Constructor dependency injection is not possible.
  • In Setter method dependency injection, even though dependent values are not ready, Setter method dependency injection will be performed.
  • In case of constructor dependency injection ,partial dependency injection is not possible, because, we have to access the constructor by passing the required no of parameter values.
  • In case of setter method dependency injection, partial dependency injection is possible , because, we are able to access setXXX() method individually.
  • IN case of constructor dependency injection, it is not simple to change the values in bean object.
  • In case of Setter method dependency injection , it is very simple to change the values in bean object.
  • In Constructor dependency injection, for every change on values a new bean object is created, because, for every change we have to call constructor explicitly.
  • In Setter method dependency injection, for every change on values new object is not created, because, for every change we can access setXXX() method explicitly.
  • Constructor dependency injection will make the bean object as "Immutable Object". Setter method dependency injection will make the bean object as "mutable Object".
  • If we provide both Constructor and setter method dependency injection to a single bean object then setter method dependency injection overrides constructor dependency injection, but, constructor dependency injection is not overriding setter cmethod dependency injection.
  • Constructor dependency injection may provide circular dependency injection. Setter method dependency injection will not provide circular dependency injection.
  • Constuctor dependency injection will give guarantee for dependency injection. Setter method dependency injection will not give guarantee for dependency injection.
  • In Spring applications, if we have more no of elements to inject then it is suggestible to use Constructor dependency injection instead of setter method dependency injection.

5. Name Spaces

5.1 p-Namespace:

  • In general, in setter method dependency injection, to specify dependent values in spring configuration file we have to use <property> tags as per the no of properties in the bean class. In this context, to remove <property> tags and to provide dependent values as atributes in <bean> tag in spring configuration file we have to use "P-Namespace".

  • Note: To use p-namespace in spring configration file we have to define "p" namespace in XSD like below.
    • xmlns:p="http://www.springframework.org/schema/p"

  • To provide value as attribute by using "p" namespace in <bean> tag we have to use the following syntax.
    • <bean id="--" class="--" p:prop_Name="value" p:prop_Name="value".../>

  • If we want to specify object referernce variable as dependent value the we have to use "- ref" along with property.
    • <bean id="--" class="--" p:prop_Name-ref="ref"/>

5.2 C-Namespace:

  • In general, in constructor  dependency injection, to specify dependent values in the spring configuration file we have to use <copnstructor-arg> tags as per the no of parameters
  • which we defined in the bean class constructor . In this context, to remove <constructor- arg> tags and to provide dependent values as attributes in <bean> tag in spring configuration file we have to use "C-Namespace".

  • Note: To use c-namespace in spring configration file we have to define "c" namespace in XSD like below.
    • xmlns:c="http://www.springframework.org/schema/c"

  • To provide value as attribute by using "c" namespace in <bean> tag we have to use the following syntax.

    • <bean id="--" class="--" c:arg_Name="value" c:arg_Name="value".../>

  • If we want to specify object referernce variable as dependent value then we have to use "- ref" along with argument_Name.

    • <bean id="--" class="--" c:arg_Name-ref="ref"/>

  • If we want to specify dependent values in beans configuration file on the basis of index values then we have to use xml code like below.

    • <bean id="--" class="--" c:_0="val1" c:_1="val2"...c:_4-ref="ref"/>

Example:

Employee.java

package com.cloud.beans;
public class Employee { 
  private String eid;
  private String ename; 
  private float esal;
  private Address eaddr;
  
  setXXX() 
  getXXX()

  public void getEmpDetails(){
    System.out.println("Employee Details"); 
    System.out.println("--------------------"); 
    System.out.println("Employee Id :"+eid); 
    System.out.println("Employee Name :"+ename); 
    System.out.println("Employee Salary :"+esal); 
    System.out.println();
    
    System.out.println("Employee Address Details"); 
    System.out.println("--------------------------"); 
    System.out.println("House Number :"+eaddr.getHno());
    System.out.println("Street :"+eaddr.getStreet());
    System.out.println("City  :"+eaddr.getCity());
    System.out.println("State :"+eaddr.getState());
  } 
}
Address.java
package com.cloud.beans;
public class Address { 
    String hno;
    String street; 
    String city; 
    String state;

    setXXX() 
    getXXX() 
}
Student.java
package com.cloud.beans;
public class Student { 
    String sid;
    String sname;
    String saddr;
    Course crs;
    public Student(String sid, String sname, 
            String saddr, Course crs) {
        this.sid=sid; this.sname=sname; this.saddr=saddr; this.crs=crs;
    }
    public void getStudentDetails(){ 
        System.out.println("Student Details"); 
        System.out.println("------------------"); 
        System.out.println("Student Id :"+sid); 
        System.out.println("Student Name :"+sname); 
        System.out.println("Student Address :"+saddr); 
        System.out.println();
        crs.getCourseDetails(); 
    }
}

Course.java

package com.cloud.beans;
public class Course { 
    String cid;
    String cname;
    int ccost;

    public Course(String cid, String cname, int ccost) { 
        this.cid=cid;
        this.cname=cname;
        this.ccost=ccost; 
    }

    public void getCourseDetails(){ 
        System.out.println("Course Details"); 
        System.out.println("--------------------"); 
        System.out.println("Course Id :"+cid); 
        System.out.println("Course Name :"+cname); 
        System.out.println("Course Cost :"+ccost);

    } 
}

applicationContext.xml

 <beans ------- xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:c="http://www.springframework.org/schema/c">

    <bean id="emp" class="com.cloud.beans.Employee" 
        p:eid="E-111" p:ename="AAA" p:esal="15000" p:eaddr-ref="addr"/> 

    <bean name="addr" class="com.cloud.beans.Address" 
        p:hno="23/3rt" p:street="M G Road" p:city="Hyd" p:state="Tel"/>

    <bean id="std" class="com.cloud.beans.Student" 
        c:sid="S-111" c:sname="AAA" c:saddr="Hyd" c:crs-ref="crs"/>

    <bean id="crs" class="com.cloud.beans.Course" 
    c:_0="C-111" c:_1="JAVA" c:_2="10000"/>

</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.Employee; import com.cloud.beans.Student;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context=
            new ClassPathXmlApplicationContext("applicationContext.xml"); 

        Employee emp=(Employee)context.getBean("emp"); emp.getEmpDetails();
        System.out.println();
        
        Student std=(Student)context.getBean("std"); 
        std.getStudentDetails();
    }
}

6. Method Injection

  • In Spring applications, bydefault, all the objects are singleton objects provided by IOC Container[ApplicationContext] . In Spring application , as part of dependency injection both the container object and contained object are having same scope then application may not get any problem, if container object and contained objects are having different scopes then application may get problem.

  • Example

    • In Spring applications, if we inject Course object in Student Object , where if provide Singleton scope to Student object and Prototype scope to Course object then For every request for Student object single Student Object is created , along with single student object single Course object is created with out checking its scope "prototype" which we provided in spring configuration file, it is voilating spring scopes rules and regulations.

Student.java

public class Student{ 
    private Course scounrse; 
    setXXX()
    getXXX()
}
Course.java 
public class Course{ -----
}

spring_beans_config.xml

<beans>
    <bean id="std" class="com.cloud.beans.Student" scope="singleton">
        <property name="scourse" ref="scourse"/> 
    </bean>
    <bean id="scourse" class="com.cloud.beans.Course" scope="prototype">
    </bean> 
</beans>

Test.java

public class Test{
    public static void main(String[] args){
        ApplicationContext context=
            new ClasspathXmlApplicationContext("/com/ cloud/cfgs/spring_beans_config.xml");
        Student std1=(Student)context.getBean("std");
        Student std2=(Student)context.getBean("std"); 
        System.out.println(std1);// a111
        System.out.println(std2);// a111 
        System.out.println(std1.getScourse());// b111 
        System.out.println(std2.getScourse());// b111
    }
}

  • To overcome the above problem Spring has provided no of solutions, where one of the solution is "Method Injection".

  • In Spring Framework, Method injection is available in two forms.
    • 1. Lookup Method Injection
    • 2. Arbitrary Method Replacement

6.1 . Lookup Method Injection

  • In case of Look Method injection, we will declare an abstract class as a factory class and an abstract method as a factory method then we will give an intemation to IOC Container about to generate a sub class for the abstract class and an implementation for the abstract method dynamically.
  • In this context, IOC Container will prepare dynamic sub classes for abstract factory class and return that objects to the test application as per the requirement.
  • In Spring Framework, IOC Container will provide dynamic sub classes by using CGLIb third party library which is managed by Spring framework internally.
  • To give an intimation to the IOC Container about the sub classes generation and implementation for Factory method by providing configuration details in spring configuration file.
  • To achieve the above requirement, we have to use "<lookup-method>" in beans configuration.

Example:

Account.java

package com.cloud.beans;
public interface Account { 
        public void create();
        public void search(); 
        public void update(); 
        public void delete();
}

CurrentAccount.java

package com.cloud.beans;
public class CurrentAccount implements Account {
    public void create() {
        System.out.println("Current Account is Created"); 
    }

    public void search() {
        System.out.println("Current Account is Identified"); 
    }

    public void update() {
        System.out.println("Current Account is Updated"); 
    }

    public void delete() {
        System.out.println("Current Account is Deleted"); 
    }
}

SavingsAccount.java

package com.cloud.beans;
public class SavingsAccount implements Account {
    public void create() {
        System.out.println("Savings Account is created"); 
    }
    
    public void search() {
        System.out.println("Savings Account is identified"); 
    }

    public void update() {
        System.out.println("Savings Account is Updated"); 
    }

    public void delete() {
        System.out.println("Savings Account is Deleted"); 
    }

}

AccountFactory.java

package com.cloud.factory; 
import com.cloud.beans.Account;
public abstract class AccountFactory {
    public abstract Account getAccount(); 
}

spring_beans_config.xml

<beans>
    <bean id="savingsAccount" class="com.cloud.beans.SavingsAccount" /> 
    <bean id="currentAccount" class="com.cloud.beans.CurrentAccount" /> 
    <bean id="savingsAccountFactory"
        class="com.cloud.factory.AccountFactory">
        <lookup-method name="getAccount" bean="savingsAccount"/>
    </bean>
    <bean id="currentAccountFactory" class="com.cloud.factory.AccountFactory">
        <lookup-method name="getAccount" bean="currentAccount"/> 
    </bean>
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.cloud.beans.CurrentAccount;
import com.cloud.beans.SavingsAccount;
import com.cloud.factory.AccountFactory;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context=
            new ClassPathXmlApplicationContext("/com/cloud/cfgs/spring_beans_config.xml"); 

        AccountFactory savingsAccountFactory=(AccountFactory)context.getBean("savingsAccountFactory"); 
        SavingsAccount savings_Account=(SavingsAccount)savingsAccountFactory.getAccount(); savings_Account.create();
        savings_Account.search();
        savings_Account.update();
        savings_Account.delete(); 

        System.out.println();

        AccountFactory currentAccountFactory=(AccountFactory)context.getBean("currentAccountFactory"); 
        CurrentAccount current_Account=(CurrentAccount)currentAccountFactory.getAccount(); current_Account.create();
        current_Account.search();
        current_Account.update();
        current_Account.delete();
    }
}

6.2 Method Replacement:

  • It is one type of method injection, where we will give an intimation to IOC Container about to replace the existed method implementation with some other method implementation.
  • To achieve Method Replacement, we have to declare an user defined bean class with a method whose implementation we want to replace and we will provide new implementation for that method by declaring a class and by implementing "MethodReplacer" interface.
  • MethodReplacer interface contains reimplement(-----) method, here we must provide our new implementation in reimplement() method.

Example:

Course.java

package com.cloud.beans; public class Course {
private String cid; private String cname;
  private int ccost;
  setXXX()
  getXXX()
  
  public void getCourseDetails(){
    System.out.println("Course Details"); 
    System.out.println("-----------------"); 
    System.out.println("Course Id :"+cid); 
    System.out.println("Course Name :"+cname); 
    System.out.println("Course Cost :"+ccost);
  } 
}

NewImpl.java

package com.cloud.beans;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;
public class NewImpl implements MethodReplacer {
      public Object reimplement(Object arg0, 
            Method arg1, Object[] arg2) throws Throwable {
            System.out.println("Course Details"); 
            System.out.println("-----------------"); 
            System.out.println("Course Id :C-222"); 
            System.out.println("Course Name :.NET"); 
            System.out.println("Course Cost :20000"); 
            return null;
      } 
}

spring_beans_config.xml

<beans>
      <bean id="newImpl" class="com.cloud.beans.NewImpl"/> 
      <bean id="course" class="com.cloud.beans.Course">
            <property name="cid" value="C-111"/> 
            <property name="cname" value="Java"/>
            <property name="ccost" value="10000"/>
            <replaced-method name="getCourseDetails" replacer="newImpl"/> 
      </bean>
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.Course;

public class Test {
  public static void main(String[] args)throws Exception {
      ApplicationContext context=
            new ClassPathXmlApplicationContext("/com/cloud/cfgs/spring_beans_config.xml"); 

      Course crs=(Course)context.getBean("course");
      crs.getCourseDetails();

  }
}


You may also like

Kubernetes Microservices
Python AI/ML
Spring Framework Spring Boot
Core Java Java Coding Question
Maven AWS