Java Spring Part 2: All about Bean

Image for post
Image for post

This is not a cooking class. Like cooking a soup process, I will show you the bean containers, scope, lifecycles, postprocessor, inheritance, and template. You will not become a chef but you should have a simple idea of how beans work in the Spring Framework.

🍳1. Cooking pot: IoC Container

From part 1, you shall have seen how Spring blends Plain Old Java Object (POJO) and XML bean together. The cookware is called Spring container. The cooking method is called Inversion of Control principle, init as IoC. In the last part, we have seen one of IoC pot, ApplicationContext. The other IoC pot is BeanFactory. The AppContext is a big pot. It contains BeanFactory to deal with beans ( Spring’s AOP); handles server messages (I18N); publishes events to its listeners, and works with web applications.

Let’s declare a BeanFactory in Java:

Resource resource = new ClassPathResource("soup.xml");  
BeanFactory factory = new XmlBeanFactory(resource);

The resource instance injects into XmlBeanFactory to create the instance of BeanFactory.

And take a look of ApplicationContext of part 1:

ApplicationContext context = new ClassPathXmlApplicationContext("com/homanspring/Beans.xml");

It’s much simpler. We can create a new instance of AppContext with the name of XML file.

🍇2. Bean and Scope

Now, let’s study the worker in the factory, Bean.

<!-- simple -->
<bean id = "..." class = "...">
<!-- lazy init -->
<bean id = "..." class = "..." lazy-init = "true">
<!-- init method -->
<bean id = "..." class = "..." init-method = "...">
<!-- destruction method -->
<bean id = "..." class = "..." destroy-method = "...">

The beans can serve in a defined kitchen, called scope. There five scopes:

  • Singleton => IoC container
  • Prototype => I can handle many objects.
  • Request => Http
  • Session => Http
  • Global-session => Global Http

You see, the Spring Framework heavily serves on the Web application. Let’s attach a scope to a bean:

<!-- singleton scope -->
<bean id = "..." class = "..." scope = "singleton">

🍝3. Test Scope

Back to the SpringExample project; in this time, we need to research how scope works in the code.

Singleton

Beans.xml, without a default value.

...
<bean id = "hello" class = "com.homanspring.Hello"
scope="singleton">
</bean>

SpringApp.java: Let’s get the chicken and display her feather.

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
"com/homanspring/Beans.xml");
Hello helloA = (Hello) context.getBean("hello");

helloA.setChicken("Yellow Chicken!");
helloA.getChicken();

Hello helloB = (Hello) context.getBean("hello");
helloB.getChicken();
}

Run,

Message: Yellow Chicken!
Message: Yellow Chicken!

The singleton stores the data in a cache. Every POJO call for the message will come from the same cache. So singleton scope is the same setting for all users.

Prototype

Beans.xml, without a default value.

...
<bean id = "hello" class = "com.homanspring.Hello"
scope="prototype">
</bean>

Run,

Message: Yellow Chicken!
Message: null

Under the prototype scope, IoC creates a new bean instance for a specific object. So the prototype is one to one relationships.

💱4. Bean Lifecycle

Initialization

In XML,

<bean id = "whiteBean" class = "examples.FishBean" init-method = "init"/>

it’s call init() in FishBean class.

public class FishBean {
public void init() {
// do some initialization work
}
}

Destruction

In XML,

<bean id = "greenBean" class = "examples.FishBean" destroy-method = "destroy"/>

It calls destroy() in FishBean class.

public class FishBean {
public void destroy() {
// do some destruction work
}
}

📑5. Test Lifecycle

Back to the SpringExample project, let’s add two lifecycle callings in Hello.java.

public class Hello {
...
public void init() {
System.out.println("Initialize cooking. Prepare the chicken.");
}

public void destroy() {
System.out.println("Chicken is destroyed.");
}
}

Beans.xml,

...
<bean id = "hello" class = "com.homanspring.Hello"
init-method = "init"
destroy-method = "destroy">
<property name = "chicken" value = "Chicken is cooking."/>
</bean>

SpringApp.java,

public static void main(String[] args) {
AbstractApplicationContext context =
new ClassPathXmlApplicationContext(
"com/homanspring/Beans.xml");

Hello mHello = (Hello) context.getBean("hello");

mHello.getChicken();
context.registerShutdownHook();
}

The registerShutdownHook() of AbstractApplicationContext will shutdown and call destroy().

Run,

Initialize cooking. Prepare the chicken.
Message: Chicken is cooking.
Chicken is destroyed.

It’s successful to call init() and destroy() methods.

You don’t need to set them for all of the beans with the same name. A default value can be set in the XML file.

<beans xmlns = ...
default-init-method = "init"
default-destroy-method = "destroy">

⏳6. BeanPostProcessor

BeanPostProcessor can give you extra options at the init processing. Let’s add a new class, MyInitHello.java.

Image for post
Image for post
public class MyInitHello implements BeanPostProcessor {}
Image for post
Image for post
public class MyInitHello implements BeanPostProcessor {

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("After Initialization: chicken is cleaned <= "+beanName+" bean");

return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Before Initialization: shop for the chicken <= "+beanName+" bean");

return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}

}

I add two system printouts. Let’s call this class at XML.

Beans.xml,

<bean id = "hello" class = "com.homanspring.Hello" 
init-method = "init"
destroy-method = "destroy">
<property name = "chicken" value = "Chicken is cooking."/>
</bean>
<bean class = "com.homanspring.MyInitHello" />

Run,

Before Initialization: shop for the chicken <= hello bean
Initialize cooking. Prepare the chicken.
After Initialization: chicken is cleaned <= hello bean
Message: Chicken is cooking.
Chicken is destroyed.

🎎7. Bean Inheritance

Let’s test the inheritance situation of two beans. This time, I want to compare two menus.

Beans.xml, secondMenu inherits to the firstMenu.

<?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-4.3.xsd">

<bean id = "firstMenu" class = "com.homanspring.MenuFirst" >
<property name = "chicken" value = "Chicken Noodle."/>
<property name = "beef" value = "Beef Pho."/>
</bean>

<bean id ="secondMenu" class = "com.homanspring.MenuSecond"
parent = "firstMenu">
<property name = "chicken" value = "Chicken Egg Soup."/>
<property name = "pork" value = "BBQ Pork"/>
</bean>

</beans>

MenuFirst.java has chicken and beef on the menu.

public class MenuFirst {
private String chicken;
private String beef;

public void getChicken() {
System.out.println("Selected chicken: "+chicken);
}
public void setChicken(String chicken) {
this.chicken = chicken;
}
public void getBeef() {
System.out.println("Selected beef: "+beef);
}
public void setBeef(String beef) {
this.beef = beef;
}
}

MenuSecond.java,

public class MenuSecond {
private String pork;
private String chicken;
private String beef;

public void getChicken() {
System.out.println("2nd-Menu Chicken: "+chicken);
}
public void setChicken(String chicken) {
this.chicken = chicken;
}

public void getBeef() {
System.out.println("2nd-Menu Beef: "+beef);
}
public void setBeef(String beef) {
this.beef = beef;
}

public void getPork() {
System.out.println("2nd-Menu Pork: "+pork);
}
public void setPork(String pork) {
this.pork = pork;
}
}

The second menu has added pork.

SpringApp.java,

public class SpringApp {

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
"com/homanspring/Beans.xml");

MenuFirst firstMenu =
(MenuFirst) context.getBean("firstMenu");

firstMenu.getChicken();
firstMenu.getBeef();

MenuSecond secondMenu =
(MenuSecond) context.getBean("secondMenu");

secondMenu.getChicken();
secondMenu.getBeef();
secondMenu.getPork();

}
}

Run,

Menu1 Chicken: Chicken Noodle.
Menu1 Beef: Beef Pho.
2nd-Menu Chicken: Chicken Egg Soup.
2nd-Menu Beef: Beef Pho.
2nd-Menu Pork: BBQ Pork

The bean of secondMenu doesn’t define beef value, so the beef inherits the value from the bean of firstMenu.

📰8. Bean Template

It’s easy to write a template for a bean.

<bean id = "templateMenu" abstract = "true" >
<property name = "chicken" value = "Chicken Noodle."/>
<property name = "beef" value = "Beef Pho."/>
<property name = "pork" value = "BBQ Pork"/>
</bean>

<bean id ="secondMenu" class = "com.homanspring.MenuSecond"
parent = "templateMenu">
<property name = "chicken" value = "Chicken Egg Soup."/>
<property name = "pork" value = "Pork Onion Soup"/>
</bean>

Characteristic of template: no class + abstract + property (value).

SpringApp.java,

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
"com/homanspring/Beans.xml");

MenuSecond secondMenu =
(MenuSecond) context.getBean("secondMenu");

secondMenu.getChicken();
secondMenu.getBeef();
secondMenu.getPork();
}

MenuSecond.java has no change. Let’s run,

2nd-Menu Chicken: Chicken Egg Soup.
2nd-Menu Beef: Beef Pho.
2nd-Menu Pork: Pork Onion Soup

The secondMenu has no beef on the menu, so it inherits the value from the templateMenu.

🎴9. Inner Bean

Like a Java class, the Bean can have inner Bean.

<bean id = "outerBean" class = "...">
<property name = "target">
<bean class = "..."/>
</property>
</bean>

Here is the example between Menu and SoupMaker.

SoupMaker.java, this is the class of an inner bean.

public class SoupMaker {
String meat;
String vegetable;

public void getVegetable() {
System.out.print("Vagetable: "+vegetable);
}

public void setVegetable(String vagetable) {
this.vegetable = vagetable;
}

public SoupMaker() {
System.out.println("SoupMaker constructor...");
}

public void getMeat() {
System.out.println("Soup kind: "+meat);
}

public void setMeat(String food) {
this.meat = food;
}

public void checkSoup() {
System.out.println("Check soup: still cooking...");
}

public void detail() {
System.out.println("Soup contains: "+meat+" and "+vegetable);
}
}

Like regular POJO, you need setter and getter for each bean related property. In addition, you can add extra functions like checkSoup() and detail().

Let’s take a look at the Beans.xml.

<bean id ="secondMenu" class = "com.homanspring.MenuSecond">
<property name = "makeSoup">
<bean class = "com.homanspring.SoupMaker">
<property name="meat" value="Chicken"></property>
<property name="vegetable" value="Tomato"></property>
</bean>
</property>
</bean>

The makeSoup is the variable in MenuSecond.java. The meat and the vegetable are the variables of SoupMaker.java.

MenuSecond.java,

public class MenuSecond {
private SoupMaker makeSoup;
public void setMakeSoup(SoupMaker makeSoup) {
this.makeSoup = makeSoup;
}

public SoupMaker getMakeSoup() {
return makeSoup;
}

public void soupChecker() {
makeSoup.checkSoup();
}

public void soupDetail() {
makeSoup.detail();
}
}

SpringApp.java,

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
"com/homanspring/Beans.xml");

MenuSecond secondMenu =
(MenuSecond) context.getBean("secondMenu");

secondMenu.soupChecker();
secondMenu.soupDetail();
}

Run,

SoupMaker constructor...
Check soup: still cooking...
Soup contains: Chicken and Tomato

Enjoy the reading!

08/15/2020

Written by

Computer Science BS from SFSU. I studied and worked on Android system since 2017. If you are interesting in my past works, please go to my LinkedIn.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store