In this tutorial, I'm going to cover how to interact with internal POJOs (Plain Old Java Objects) in spring application. Also I'm going to cover why spring need auto-wiring between two POJOs.
How it works
Sometime the POJO instances or beans need to refer another POJO instance to complete application's functionality (i.e. a POJO instance is dependent on another POJO instance). To access a POJO inside another POJO, we need to specify the bean reference inside the configuration file. Often, this dependency need to handle manually by programmers. But, in large commercial application, we need a more reliable way to resolve this inner dependency. That's where spring auto-wiring comes in place.
By auto-wiring, spring container establish a relationship between two POJO instances. By enebeling auto-wiring, we let spring to resolve collabration between beans automatically. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.
The autowiring functionality has four modes. They are-
Mode | Explanation |
---|---|
no |
(Default) No auto-wiring. Bean references must be defined by ref elements. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system. |
byName |
Auto-wiring by property name. Spring looks for a bean with the same name as the property that needs to be auto-wired. For example, if a bean definition is set to auto-wire by name and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master and uses it to set the property. |
byType |
Lets a property be auto-wired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType auto-wiring for that bean. If there are no matching beans, nothing happens (the property is not set). |
constructor |
Analogous to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. |
Program structure
Github repository link: click here
Program logic
Let's create a java class named Laptop
having four local variable, name
, price
, motherboard
, processor
. motherboard is an object of Motherboard
class and processor is an object of Processor
class.
So, we can clearly see that, Laptop
class has inner dependency on Motherboard
and Processor
class. In normal programming approach, we need to declare each of dependent object with new
operator. But, whenever we use new
to declare object, we are hardcoding the value (the program will have tight coupling). So, we are going to resolve this problem by declaring POJO instances. Now, we don't need to hardcoding values inside our program logic.
// Filename: Laptop.java
package com.example.SpringAutowire;
public class Laptop {
private String name;
private int price;
private Motherboard motherboard;
private Processor processor;
// constructors
public Laptop() {}
public String getName() {
return name;
}
// getters and setters
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Motherboard getMotherboard() {
return motherboard;
}
public void setMotherboard(Motherboard motherboard) {
this.motherboard = motherboard;
}
public Processor getProcessor() {
return processor;
}
public void setProcessor(Processor processor) {
this.processor = processor;
}
public void getLaptopDetails() {
System.out.println("Laptop Name: "+name);
System.out.println("Laptop price: "+price);
System.out.println("Motherboard: "+motherboard.getName());
System.out.println("Processor: "+processor.getName());
}
}
// Filename: Motherboard.java
package com.example.SpringAutowire;
public class Motherboard {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// Filename: Processor.java
package com.example.SpringAutowire;
public class Processor {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now, It's time to define POJO instances for the above java classes. To do this, I'm going to create a .xml
file named Beans.xml
inside my application root class-path.
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
Now, inside those <beans>
</beans>
tag, we are going to define our individual POJO instances, with some values.
<bean id="laptop" class="com.example.SpringAutowire.Laptop">
<property name="name" value="dell vostro 1450s"/>
<property name="price" value="45000"/>
<property name="motherboard" ref="motherboard"/>
<property name="processor" ref="processor"/>
</bean>
<bean id="processor" class="com.example.SpringAutowire.Processor">
<property name="name" value="intel i3 11g"/>
</bean>
<bean id="motherboard" class="com.example.SpringAutowire.Motherboard">
<property name="name" value="gigabyte h81ms v2"/>
</bean>
Note that inside laptop bean, the value of motherboard
and processor
is referencing (ref
attribute inside property
tag refer to another POJO. It's not mandatory to place the POJO instances inside same xml file) to another POJO instances, which are declared after laptop
POJO. By doing this, we have resolve internal POJO dependency. Now, if you run your application (with driving code), it will work successfully.
Autowiring POJOs
So far we resolve internal POJO dependency. But, still we writing POJO dependency by ourself manually. By using autowire
attribute inside a <bean>
tag, we let spring to automatically fetch the internal beans.
<bean id="laptop" class="com.example.SpringAutowire.Laptop" autowire="byName">
<property name="name" value="dell vostro 1450s"/>
<property name="price" value="45000"/>
</bean>
Note that, now laptop no longer has processor
and motherboard
value defined. By define autowire="byName"
, srping will search for the required beans by its name, and whenever match found, spring will automatically refer the bean at compile time.
Driving code
Now, we are ready to write our final pice of code or the driving code. Now create a java class containing the main method(if you create your project using maven or groovy project template, you are provided a java class containing main mathod, just use those file).
Inside those class declare a ApplicationContext
variable and
define with ClassPathXmlApplicationContext()
with parameter the string representation of your configuration xml file name with fully specified path (in my case, my xml file is placed at the root location, so I no need to enter the fully specified path name). Make sure that this variable is declared as static, so that we can access it from main method.
The ApplicationContext
interface is responsible to create the spring IOC container(if you are not familiar with IOC, click here and go through the documentation). ClassPathXmlApplicationContext
class is a subclass which implemented ApplicationContext
interface. There are many other subclass available to create IOC container.
Now, inside the main method of our code, create a variable of type Laptop and instantiated it with a defined bean. In this case context.getBean("laptop", Laptop.class)
return a variable of type Laptop
. The first argument of getBean refers to the bean name as string and the second argument refers to the actual class. By default getBean()
method's return type is java.lang.Object
. The second argument in the getBean()
method actually used to typecast the value. So we no need to typecast it manually. In the below code, I'm typecasting the value to Laptop.class
type.
package com.example.SpringAutowire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
private static ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
public static void main( String[] args ){
Laptop laptop = context.getBean("laptop", Laptop.class);
laptop.getLaptopDetails();
}
}
Top comments (0)