Spring 5 lookup method dependency injection example


In the Spring framework, most of the time we do the setter-based or constructor-based dependency injection but in this tutorial, we will learn about one more type of dependency injection i.e. method or lookup method injection. Lookup method injection is the ability of the container to override methods on container managed beans, to return the lookup result for another named bean in the container. To do this Spring provide <looup-method /> child element of <bean /> element.

Lookup method: If a method not having any implementation or if method required any dependencies, we can consider those methods as a lookup method.

The Spring framework implements method injection by using bytecode generation from the CGLIB library to generate dynamically a subclass that overrides the method. The lookup typically involves a prototype bean.

Consider the below snippet of the interface, abstract class, and concrete class.

public interface Employee {

	public void hike();

}

In the above interface, we can consider the hike() as a lookup method. For the abstract class, it may have the abstract method or it may not have.

abstract public class Movies {

	abstract public void showTime();

}

Here we can consider showTime() method as lookup method to provide its implementation. And if you have a concrete class with a fully implemented method.

public class Adventure {

	public void bikeAdventure() {

		// implementation

	}
}

If you want to override the bikeAdventure() method implementation, then we can consider it as a lookup method.

Note: In lookup method injection, we are basically overriding the method and provide its implementation.

Let’s check the complete example of all possible cases.

Technologies Used

Check the list of all the technologies used in this example.

  1. Spring-5.0.2.RELEASE
  2. JDK 8
  3. Eclipse IDE and
  4. CGLIB library

Spring Beans

Create the four different bean classes for method injection. In my example, I have Engine bean class for injecting value to lookup method using setter-based di.

Engine.java
package org.websparrow.beans;

public class Engine {

	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

And a Car interface has Engine type lookup method.

Car.java
package org.websparrow.beans;

public interface Car {

	public Engine myCarEngine();

}

An abstract class Bus having an abstract Engine type lookup method.

Bus.java
package org.websparrow.beans;

abstract public class Bus {

	abstract public Engine myBusEngine();
}

And finally, a concrete class Truck having a full implemented Engine type lookup method.

Truck.java
package org.websparrow.beans;

public class Truck {

	public Engine myTruckEngine() {
		Engine e = new Engine();
		e.setName("ASHOKA Truck Engine");
		return e;
	}
}

Spring Beans Configuration

In the configuration file, use the <looup-method /> child element of <bean /> element. To provide the implementation of a method or override the method, pass the method name to the name attribute and bean reference id.

spring.xml
<?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">

	<!-- for car interface provide look-up method di -->

	<bean id="car" class="org.websparrow.beans.Car">
		<lookup-method name="myCarEngine" bean="e" />
	</bean>

	<bean id="e" class="org.websparrow.beans.Engine">
		<property name="name" value="BMW Car Engine" />
	</bean>

	<!-- for bus abstract class provide look-up method di -->

	<bean id="bus" class="org.websparrow.beans.Bus">
		<lookup-method name="myBusEngine" bean="e1" />
	</bean>

	<bean id="e1" class="org.websparrow.beans.Engine">
		<property name="name" value="Volvo Bus Engine" />
	</bean>

	<!-- for truck concrete class provide look-up method di -->

	<bean id="truck" class="org.websparrow.beans.Truck">
		<lookup-method name="myTruckEngine" bean="e2" />
	</bean>

	<bean id="e2" class="org.websparrow.beans.Engine">
		<property name="name" value="TATA Truck Engine" />
	</bean>

</beans>

Run it

To test it load the configuration into the IoC container and run it.

Test.java
package org.websparrow.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.websparrow.beans.Bus;
import org.websparrow.beans.Car;
import org.websparrow.beans.Truck;

public class Test {
	public static void main(String[] args) {

		ApplicationContext ap = new ClassPathXmlApplicationContext("spring.xml");

		System.out.println("............CAR...........");
		Car car = (Car) ap.getBean("car");
		System.out.println(car.myCarEngine().getName());

		System.out.println("............BUS...........");
		Bus bus = (Bus) ap.getBean("bus");
		System.out.println(bus.myBusEngine().getName());

		System.out.println("............TRUCK...........");
		Truck truck = (Truck) ap.getBean("truck");
		System.out.println(truck.myTruckEngine().getName());

	}
}
Output:

You will get the following result on your console log.

............CAR...........
BMW Car Engine
............BUS...........
Volvo Bus Engine
............TRUCK...........
TATA Truck Engine

How does it work?

In most of the scenario, we do the setter or constructor based dependency injection for Collection, Arrays, String, etc. and also create the implementation. So by using Spring XML file, we create the object of bean classes and do dependency injection. If you want to provide implementation is it possible to write code in the XML file, it is not possible, we can create bean class and into bean class, we can do dependency injection.

To provide lookup method injection Spring will provide the implementation classes. At runtime, Spring generates proxy classes extended from the original class using CGLIB library and by generating the proxy class, it will override the lookup method. We can see the implementation class by using getClass().getCanonicalName() method. To test it, replace the NewTest class with the below code.

NewTest.java
package org.websparrow.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.websparrow.beans.Bus;
import org.websparrow.beans.Car;
import org.websparrow.beans.Truck;

public class NewTest {

	public static void main(String[] args) {

		ApplicationContext ap = new ClassPathXmlApplicationContext("spring.xml");

		System.out.println("............CAR...........");
		Car car = (Car) ap.getBean("car");
		System.out.println(car.getClass().getCanonicalName());
		System.out.println(car.myCarEngine().getName());

		System.out.println("............BUS...........");
		Bus bus = (Bus) ap.getBean("bus");
		System.out.println(bus.getClass().getCanonicalName());
		System.out.println(bus.myBusEngine().getName());

		System.out.println("............TRUCK...........");
		Truck truck = (Truck) ap.getBean("truck");
		System.out.println(truck.getClass().getCanonicalName());
		System.out.println(truck.myTruckEngine().getName());

	}
}

About the Author

Atul Rai
I like sharing my experiments and ideas with everyone by writing articles on the latest technological trends.