Method Injection
IN this tutorial, we are going to discuss method injection in the spring framework. By default, in Spring applications, all the objects are singleton objects provided by IOC Container [ApplicationContext]. As part of dependency injection, in the Spring application, both container and contained objects have the same scope. The application may not get any problems. If container objects and contained objects have different scopes, then the application may get the 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 the 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 several solutions, where one of the solutions 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 the case of the Look Method injection, we will declare an abstract class as a factory class and an abstract method as a factory method. Then, we will intimate IOC Container about generating a sub-class for the abstract class and implementing the abstract method dynamically.
In this context, IOC Container will prepare dynamic subclasses for abstract factory class and return those objects to the test application as per the requirement. In Spring Framework, IOC Container will provide dynamic sub-classes using CGLIb third party library, which is internally managed by the Spring framework.
Inform the IOC Container about the subclasses generation and implementation for the Factory method by providing configuration details in the spring configuration file. To achieve the above requirement, we have to use “” in the 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 the IOC Container about replacing the existing method implementation with some other method implementation.
To achieve Method Replacement, we must declare a user-defined bean class with a method whose implementation we want to replace. We will provide a new implementation for that method by declaring a class and implementing the “MethodReplacer” interface. MethodReplacer interface contains reimplement (—) method, and here we must provide our new implementation in reimplement() method.
package com.ashok.spring.core.bean.methodinjection.methodreplacement.beans;
/**
*
* @author Ashok Kumar
*
*/
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;
/**
*
* @author Ashok Kumar
*
*/
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