Recent Posts

Friday, 14 June 2019

Method Injection

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 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.
E.g.
     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 without checking its scope "prototype" which we provided in spring configuration file, it is violating spring scopes rules and regulations.
package com.ashok.spring.core.bean.methodinjection.beans;
/**
 * 
 * @author Ashok Kumar
 *
 */
public class Course {
   private String courseName;
   private String courseId;
   private double price;

   public String getCourseName() {
      return courseName;
   }

   public void setCourseName(String courseName) {
      this.courseName = courseName;
   }

   public String getCourseId() {
      return courseId;
   }

   public void setCourseId(String courseId) {
      this.courseId = courseId;
   }

   public double getPrice() {
      return price;
   }

   public void setPrice(double price) {
      this.price = price;
   }
}
package com.ashok.spring.core.bean.methodinjection.beans;
/**
 * 
 * @author Ashok Kumar
 *
 */
public class Student {
   private String studentName;
   private String studentId;
   private Course studentCourse;

   public Course getStudentCourse() {
      return studentCourse;
   }

   public void setStudentCourse(Course studentCourse) {
      this.studentCourse = studentCourse;
   }

   public String getStudentName() {
      return studentName;
   }

   public void setStudentName(String studentName) {
      this.studentName = studentName;
   }

   public String getStudentId() {
      return studentId;
   }

   public void setStudentId(String studentId) {
      this.studentId = studentId;
   }
}
<?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-3.0.xsd">

   <bean id = "student" class = "com.ashok.spring.core.bean.methodinjection.beans.Student" scope="singleton">
      <property name = "studentName" value = "Ashok Kumar"/>
      <property name = "studentId" value = "Stu006"/>
      <property name = "studentCourse" ref = "course"/>
   </bean>
    <bean id = "course" class = "com.ashok.spring.core.bean.methodinjection.beans.Course" scope="prototype">
      <property name = "courseName" value = "Hadoop"/>
      <property name = "courseId" value = "Hadoop2019"/>
      <property name = "price" value = "15000"/>
   </bean>
</beans>
package com.ashok.spring.core.bean.methodinjection.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ashok.spring.core.bean.methodinjection.beans.Student;

/**
 * 
 * @author Ashok Kumar
 *
 */
public class TestSpringApplication {
   @SuppressWarnings("resource")
   public static void main(String[] args) {
      String configFile = "/com/ashok/spring/core/bean/methodinjection/config/applicationContext.xml";
      ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
      Student student = (Student) context.getBean("student");
      System.out.println(student);
      System.out.println(student);
      System.out.println(student.getStudentCourse());
      System.out.println(student.getStudentCourse());
   }
}
Output
com.ashok.spring.core.bean.methodinjection.beans.Student@4d41cee
com.ashok.spring.core.bean.methodinjection.beans.Student@4d41cee
com.ashok.spring.core.bean.methodinjection.beans.Course@3712b94
com.ashok.spring.core.bean.methodinjection.beans.Course@3712b94
     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

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 intimation 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.
E.g
package com.ashok.spring.core.bean.methodinjection.lookup.beans;

/**
 * 
 * @author ashok.mariyala
 *
 */
public interface Account {
   public void create();

   public void search();

   public void update();

   public void delete();
}
package com.ashok.spring.core.bean.methodinjection.lookup.beans;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class CurrentAccount implements Account {
   @Override
   public void create() {
      System.out.println("Current Account is Created");
   }

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

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

   @Override
   public void delete() {
      System.out.println("Current Account is Deleted");
   }
}
package com.ashok.spring.core.bean.methodinjection.lookup.beans;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class SavingsAccount implements Account {
   @Override
   public void create() {
      System.out.println("Savings Account is Created");
   }

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

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

   @Override
   public void delete() {
      System.out.println("Savings Account is Deleted");
   }
}
<?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-3.0.xsd">

 <bean id="savingsAccount"
  class="com.ashok.spring.core.bean.methodinjection.lookup.beans.SavingsAccount" />
 <bean id="currentAccount"
  class="com.ashok.spring.core.bean.methodinjection.lookup.beans.CurrentAccount" />
 <bean id="savingsAccountFactory"
  class="com.ashok.spring.core.bean.methodinjection.lookup.factory.AccountFactory">
  <lookup-method name="getAccount" bean="savingsAccount" />
 </bean>
 <bean id="currentAccountFactory"
  class="com.ashok.spring.core.bean.methodinjection.lookup.factory.AccountFactory">
  <lookup-method name="getAccount" bean="currentAccount" />
 </bean>
</beans>
package com.ashok.spring.core.bean.methodinjection.lookup.factory;

import com.ashok.spring.core.bean.methodinjection.lookup.beans.Account;

/**
 * 
 * @author ashok.mariyala
 *
 */
public abstract class AccountFactory {
   public abstract Account getAccount();
}
package com.ashok.spring.core.bean.methodinjection.lookup.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ashok.spring.core.bean.methodinjection.lookup.beans.CurrentAccount;
import com.ashok.spring.core.bean.methodinjection.lookup.beans.SavingsAccount;
import com.ashok.spring.core.bean.methodinjection.lookup.factory.AccountFactory;

/**
 * 
 * @author Ashok Kumar
 *
 */
@SuppressWarnings("resource")
public class TestSpringApplication {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("/com/ashok/spring/core/bean/methodinjection/lookup/config/applicationContext.xml");
      AccountFactory sAccountFactory = (AccountFactory) context.getBean("savingsAccountFactory");
      SavingsAccount sAccount = (SavingsAccount) sAccountFactory.getAccount();
      sAccount.create();
      sAccount.search();
      sAccount.update();
      sAccount.delete();
      System.out.println();
      AccountFactory cAccountFactory = (AccountFactory) context.getBean("currentAccountFactory");
      CurrentAccount cAccount = (CurrentAccount) cAccountFactory.getAccount();
      cAccount.create();
      cAccount.search();
      cAccount.update();
      cAccount.delete();
   }
}
Output
Savings Account is Created
Savings Account is Identified
Savings Account is Updated
Savings Account is Deleted

Current Account is Created
Current Account is Identified
Current Account is Updated
Current Account is Deleted
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 a 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.
package com.ashok.spring.core.bean.methodinjection.methodreplacement.beans;

public class Course {
   private String cid;
   private String cname;
   private int ccost;

   public String getCid() {
      return cid;
   }

   public void setCid(String cid) {
      this.cid = cid;
   }

   public String getCname() {
      return cname;
   }

   public void setCname(String cname) {
      this.cname = cname;
   }

   public int getCcost() {
      return ccost;
   }

   public void setCcost(int ccost) {
      this.ccost = ccost;
   }

   @Override
   public String toString() {
      return "Course [cid=" + cid + ", cname=" + cname + ", ccost=" + ccost + "]";
   }
}
package com.ashok.spring.core.bean.methodinjection.methodreplacement.impl;

import java.lang.reflect.Method;

import org.springframework.beans.factory.support.MethodReplacer;

public class MethodReplacerImpl implements MethodReplacer {
   @Override
   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 : Spring Boot");
      System.out.println("Course Cost :10000");
      return null;
   }
}
<?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-3.0.xsd">

 <bean id="newImpl" class="com.ashok.spring.core.bean.methodinjection.methodreplacement.impl.MethodReplacerImpl" />
 <bean id="course" class="com.ashok.spring.core.bean.methodinjection.methodreplacement.beans.Course">
  <property name="cid" value="C-111" />
  <property name="cname" value="Java" />
  <property name="ccost" value="5000" />
  <replaced-method name="toString" replacer="newImpl" />
 </bean>
</beans>
package com.ashok.spring.core.bean.methodinjection.methodreplacement.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ashok.spring.core.bean.methodinjection.methodreplacement.beans.Course;

/**
 * 
 * @author Ashok Kumar
 *
 */
@SuppressWarnings("resource")
public class TestSpringApplication {
   public static void main(String[] args) {
      String configFile = "/com/ashok/spring/core/bean/methodinjection/methodreplacement/config/applicationContext.xml";
      ApplicationContext context = new ClassPathXmlApplicationContext(configFile);
      Course course = (Course) context.getBean("course");
      System.out.println(course);
   }
}
Output
Course Details
-----------------
Course Id : C-222
Course Name : Spring Boot
Course Cost :10000
null

Next Tutorial : Bean Validations in spring

Previous Tutorial : Beans Autowiring

No comments:

Post a Comment