Thursday, October 27, 2022

What is bean In Spring Framework?

What is Spring Bean?

  • Bean is a Software Reusable Component, it is a normal java class contains properties and the corresponding setXXX(-) and getXXX() methods and which are created and managed by IOC Container in Spring Framework.
Rules and Regulations to write Bean classes:
  • Bean classes must be POJO classes, they must not extend or implement any predefined Library except java.io.Serializable marker interface.
  • Bean must be declared as "public" , "Non-abstract" and "non-final".
    • The main intention of declaring bean class as "public" is to make available bean class scope to IOC Container in order to create objects.
    • The main intention to declare bean class as "Non-abstract" is to allow to create object . 
    • The main intention to declare bean classes as "Non-final" is to extend one bean class to another bean class in order to improve reusability.
  • In Bean classes, we have to declare all properties as "private" and all behaviors as "public", it will improve "Encapsulation".
  • If we want to provide any constructor in the bean class then provide a constructor, it must be a 0-arg constructor and a "public" constructor, because, IOC Container will search and execute public and 0-arg constructors while instantiating bean.
  • If we want to use Beans in Spring applications then we must configure those bean classes in the spring beans configuration file, because IOCContainer will recognize and create Bean objects by getting bean class details from the beans configuration file only.


There are three ways to provide bean configurations in spring applications.

  1. XML Configuration
  2. Java Based Configuration 
  3. Annotations Configuration

1. XML  Configuration

  • To provide beans configurations in the beans configuration file we have to use the following XML tags.
  • <beans>
       <bean id="--" name="--" class="--" scope="--"> 
          <property name="--" value="--"/>
       </bean> 
    </beans>
  • Where <beans> tag is the root tag in the beans configuration file.
  • Where <bean> tag is able to provide configuration details of a particular bean class
  • Where "class" attribute in <bean> is able to provide fully qualified name of the bean class.
  • Where <property> attribute is able to represent a particular property[variable] in bean class and it will set the specified value to the respective bean property by executing setXXX(-) method.

Q)What is the difference between "id" attribute and "name" attribute in <bean> tag?

  • 'id' attribute is able to take exactly one identity to the bean object, it will not allow more than one identity.
  • 'name' attribute in <bean> tag is able to allow more than one identity name to the bean object, where in multiple values only first value is treated as th actual bean identity and the remaining names are alias names for the bean object.

  • In this context, while providing alias names to the bean object we have to use either ',' or ';' or [space] as delimiter[seperator].

Example 1:

<beans>
    <bean id="bean1" class="com.cloud.beans.MyBean"/>
</beans>

MyBean mb=(MyBean)ctx.getBean("bean1"); 
Status: Valid.
Example 2:

<beans>
    <bean id="bean1 bean2 bean3" class="com.cloud.beans.MyBean"/>
</beans>

MyBean mb=(MyBean)ctx.getBean("bean1");
Status: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
    No bean named 'bean1' is defined

SImilarily the following cases are also be invalid.
<bean id="bean1,bean2,bean3" class="MyBean"/>->INvalid
<bean id="bean1;bean2;bean3" class="MyBean"/>->Invalid 
<bean id="bean1bean2bean3" class="MyBean"/>-> Valid
Example 3:

<beans>
    <bean name="bean1" class="MyBean"/>
</beans>

MyBean mb=(MyBean)ctx.getBean("bean1"); 
Status: Valid

Example 4:

<bean name="bean1 bean2 bean3" class="MyBean"/> 

MyBean mb1=ctx.getBean("bean1");
MyBean mb2=ctx.getBean("bean2");
MyBean mb3=ctx.getBean("bean3");
Status: Valid

Similarily the following cases are also be valid.
<bean name="bean1,bean2,bean3" class="MyBean"/>
<bean name="bean1;bean2;bean3" class="MyBean"/>

Note: It is possible to use both 'id' attribute  and 'name' attribute in single <bean> tag.

Example 5:

<bean id="bean1" name="bean2" class="MyBean"/> 

MyBean mb1=ctx.getBean("bean1");
MyBean mb2=ctx.getBean("bean2");
Status: Valid.

Note: It is possible to provide bean alias names explicitly from 
out side of the bean definition in configuration file by using 
<alias> tag.
<alias name="--" alias="--"/>

Where "name" attribuite will take bean logical name which we specified 
with "id" attribute in beans configuration file.
Where "alias" attribute will take alias name.

Example 6:

<beans>
    <bean name="bean1" class="MyBean"/> 
    <alias name="bean1" alias="bean2"/> 
    <alias name="bean2" alias="bean3"/> </bean>
</beans>

MyBean mb1=ctx.getBean(bean1); --> Valid 
MyBean mb2=ctx.getBean(bean2); --> Valid 
MyBean mb3=ctx.getBean(bean3); --> Valid
2. JAVA Based Configuration

  • In Spring, upto Spring2.4 version Spring beans configuration file is mandatory to configure bean classes and their metadata, but, Right from the Spring3.x version Spring beans configuration file is optional, because, the SPring3.x version has provided Java Based Configuration as a replacement for XML documents.

If we want to use Java Based Configuration as an alternative to Spring beans configuration file in Spring applications then we have to use the following steps.

  • Create Bean classes as per the requirement.

  • Create Beans configuration class with the following annotations.
    • org.springframework.context.annotation.@Configuration
    • It able to represent a class as configuration class. org.springframework.context.annotation.@Bean
    • It will be used at method to represent the return object is bean object.

  • In Test class, Create ApplicationContext object with the org.springframework.context.annotation.AnnotationConfigpplicationContext implementation class.

    • ApplicationContext context=new AnnotationConfigApplicationContext(BeanConfig.class);

  • Get Bean object from ApplicationContext by using the following method.

    • public Object getaBean(Class c)
    • EX: Bean b=context.getBean(Bean.class);

  • Access business methods from Bean.

Example:

HelloBean.java:
package com.cloud.beans;
public class HelloBean { 
    static {
        System.out.println("Bean Loading....."); 
    }
    public HelloBean() { 
        System.out.println("Bean Created....");

    }
    public String sayHello() {
        return "Hello User"; 
    }
}
HelloBeanConfig.java:
package com.cloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.cloud.beans.HelloBean;
@Configuration
public class HelloBeanConfig {
    @Bean
    public HelloBean helloBean() {
        return new HelloBean(); 
    }
}

Test.java:

package com.cloud.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; 
import com.cloud.beans.HelloBean;
import com.cloud.config.HelloBeanConfig;

public class Test {
    public static void main(String[] args) throws Exception{
        ApplicationContext context = new 
            AnnotationConfigApplicationContext(HelloBeanConfig.class);
        HelloBean bean = (HelloBean)context.getBean("helloBean");
        System.out.println(bean.sayHello()); }
}
3. Annotations Based Configuration

  • Starting from Spring 2.5 it became possible to configure the dependency injection using annotations. So instead of using XML to describe a bean wiring, you can move the bean configuration into the component class itself by using annotations on the relevant class, method, or field declaration.
  • Annotation injection is performed before XML injection. Thus, the latter configuration will override the former for properties wired through both approaches.
  • Annotation wiring is not turned on in the Spring container by default. So, before we can use annotation-based wiring, we will need to enable it in our Spring configuration file. So consider the following configuration file in case you want to use any annotation in your Spring application.

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context = "http://www.springframework.org/schema/context"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   <!-- bean definitions go here -->
</beans>

  • Once <context:annotation-config/> is configured, you can start annotating your code to indicate that Spring should automatically wire values into properties, methods, and constructors. Let us look at a few important annotations to understand how they work −

1. @Required 

  • The @Required annotation applies to bean property setter methods.

2. @Autowired

  • The @Autowired annotation can apply to bean property setter methods, non-setter methods, constructor and properties.

3.@Qualifier

  • The @Qualifier annotation along with @Autowired can be used to remove the confusion by specifiying which exact bean will be wired.

4. JSR-250 Annotations

  • Spring supports JSR-250 based annotations which include @Resource, @PostConstruct and @PreDestroy annotations.

Check Spring-Beans-AutoWiring for more details about the above annotation  

Bean Scopes

  • In J2SE applications, we are able to define scopes to the data by using the access modifiers like public, protected, <default> and private.
  • Similarly, in the Spring framework to define scopes to the beans spring framework has provided the following scopes.

1. Singleton Scope:
<beans>
	<bean id="bean1" class="com.cloud.MyBean" scope="singleton"/>
	<bean id="bean2" class="com.cloud.MyBean" scope="singleton"/> 
</beans>

System.out.println(ctx.getBean("bean1"));//MyBean@a111 
System.out.println(ctx.getBean("bean1"));//MyBean@a111 

System.out.println(ctx.getBean("bean2"));//MyBean@a222 
System.out.println(ctx.getBean("bean2"));//MyBean@a222

 2. Prototype Scope:

  • It is not the default Scope in the Spring framework.
  • In Spring applications, if we provide "prototype" scope in bean configuration file then IOCContainer will ceate a new Bean object at each and every time of calling the getBean(--) method.

<beans>

	<bean id="bean1" class="com.cloud.MyBean" scope="prototype"/>
	<bean id="bean2" class="com.cloud.MyBean" scope="prototype"/> 
</beans>

System.out.println(ctx.getBean("bean1"));//MyBean@a111 
System.out.println(ctx.getBean("bean1"));//MyBean@a222 
System.out.println(ctx.getBean("bean2"));//MyBean@a333 
System.out.println(ctx.getBean("bean2"));//MyBean@a444

3. Request Scope:

  • This scope is not usefull in Standalone Applications[Spring Core MOdule], it will be used in Web applications which are prepared on the basis of Spring Web module. RequestScope is able to create a seperate bean object for each and every request object.

4. Session Scope:

  • This Scope will be used in web applications that are prepared on the basis of the Spring web module and it is not applicable in Standalone Applications.
  • Session scope allows the creation of a separate bean object for each and every Session object in web applications.

5. Global Session Scope:

  • This scope is not useful in standard applications, it is useful in portlet applications which are prepared on the basis of the Spring web module.
  • Global Session scope allows to creation of a separate bean object for each and every portlet Session.

6. application Scope:

  • This scope is not useful in standalone Applications, it is usefull in web applications prepared on the basis of the Spring web module.
  • ApplicationScope allows to the creation of a separate bean object for each and every ServletContext object.

7. webSocketScope:

  • This scope is usefull in web applications which are prepared on the basis of spring web module.
  • websocket scope allows to create a seperate bean object for single websocket lifecycle.


Note:

  • If we use the scopes like request, session, global session, application, WebSocket,... in standalone applications which are prepared on the basis of the spring core module then Container will rise an exception like "java.lang.IllegalStateException"
  • Spring Framework has provided an environment to customize the existing scopes , but, it is not suggestible. Spring framework has provided an environment to create new scopes in spring applications.

8. Custom Scopes

  • To define and use custom scopes in Spring Framework we have to use the following steps.

    • 1. Create User Defined Scope class.
    • 2. Register User defined Scope in Spring beans configuration file. 
    • 3. Use User defined Scope to the Beans in the beans configuration file.

1. Create User- defined Scope class:

  • Declare a user-defined class.
  • Implement org.springframework.beans.factory.config.Scope interface to User defined class.
  • Implement the following Scope interface methods in User defined class.
    • get(--): 
      • It able to generate a bean object from Scope. public Object get(String name, ObjectFactory factory) 
    • remove(): 
      • It able to remove bean object from Scope.
      • public Object remove(String name)
    • getConversationalId(): 
      • It is able to provide an id value of the scope if any.
      • EX: IN Session scope, generating sessionId. public String getConversationId()

  • registerDestructionCallback(): 
    • It will be executed when the bean object is destroyed in the Scope
    • public void registerDestructionCallback(String name, Runnable r)

  • resolveContextualObject(): 
    • It will resolve the situation where Multiple Context objects associated with the keys.
    • public Object resolveContextualObject(String name)

    Note: 

  • From the above methods, get() and remove() methods are mandatory to implement and all the remaining methods are optional.

2. Register User defined Scope in Spring beans configuration File:

  • Configureorg.springframework.beans.factory.config.CustomScopeConfigurer class as a bean.
  • Declare "scopes" as property in CustomScopeConfigurer
  • Declare "map" under scopes property.
  • Declare "entry" under the "map".
  • Declare "key" in "entry" with User defined scope name and provide value as USer defined SCope object.

3. Apply User defined Scope to bean definitions:

  • Use "scope" attribute in <bean> tag to apply user-defined scope.
        Note: 
  • In the following example, we have defined threadScope as user-defined scope, that is, it able to create a separate bean object for each and every thread.


Example:

CustomThreadLocal.java 

package com.cloud.scopes; 
import java.util.HashMap;
public class CustomThreadLocal extends ThreadLocal<Object> {
 	@Override
	protected Object initialValue() {
		return new HashMap<String, Object>();
	} 
}

ThreadScope.java

package com.cloud.scopes; import java.util.Map;

import org.springframework.beans.factory.ObjectFactory; 
import org.springframework.beans.factory.config.Scope;

public class ThreadScope implements Scope {

	Map<String, Object> scope = null;
	CustomThreadLocal threadLocal = new CustomThreadLocal(); 
        @Override
	public Object get(String name, ObjectFactory objectFactory) {
		scope = (Map<String, Object>)threadLocal.get(); 
                Object obj = scope.get(name);
		if(obj == null) {
			obj = objectFactory.getObject();
			scope.put(name, obj); 
		}
		return obj; 
	}

	@Override
	public String getConversationId() {
		// TODO Auto-generated method stub return null;
	}

	@Override
	public void registerDestructionCallback(String arg0, Runnable arg1) {
		// TODO Auto-generated method stub 
	}

	@Override
	public Object remove(String name) {
		Object obj = scope.remove(name);
		return obj; 
	}

	@Override
	public Object resolveContextualObject(String arg0) {
		// TODO Auto-generated method stub
		return null; 
	}
}

HelloBean.java

package com.cloud.beans;
public class HelloBean { 
	public HelloBean() {
		System.out.println("HelloBean Object is created"); 
	}
	public String sayHello() {
		return "Hello User from "+Thread.currentThread().getName()+" Scope";
	} 
}

Test.java

package com.cloud.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.HelloBean; import com.cloud.scopes.ThreadScope;

public class Test {

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

		HelloBean bean1 = (HelloBean)context.getBean("helloBean"); 
		HelloBean bean2 = (HelloBean)context.getBean("helloBean"); 
		
		System.out.println(bean1);
		System.out.println(bean2);
		System.out.println(bean1 == bean2); 
		System.out.println(bean1.sayHello()); 
		System.out.println(bean2.sayHello());

		ThreadScope threadScope = (ThreadScope)context.getBean("threadScope"); 
		HelloBean bean3 = (HelloBean)threadScope.remove("helloBean"); 
		System.out.println(bean3);

		HelloBean bean4 = (HelloBean)context.getBean("helloBean"); 
		HelloBean bean5 = (HelloBean)context.getBean("helloBean"); 
		
		System.out.println(bean4);
		System.out.println(bean5);
		System.out.println(bean4 == bean5); 
		System.out.println(bean4.sayHello()); 
		System.out.println(bean5.sayHello());
} 
}

applicationContext.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">

	<bean id="helloBean" class="com.cloud.beans.HelloBean" scope="thread"/> 
	<bean id="threadScope" class="com.cloud.scopes.ThreadScope"/>

	<bean id="scopeConfigurer" class=
			"org.springframework.beans.factory.config.CustomScopeConfigurer"> 
		<property name="scopes">
			<map>
			<entry key="thread" value-ref="threadScope"/>
			</map> 
		</property>
	</bean> 
</beans>
1. Bean LifeCycle

  • In spring framework applications, when IOC Container recognizes all the beans definitions in beans configuration file then IOC Container will execute that bean by using the following lifecycle actions.
    • 1. Bean Class Loading 
    • 2. Bean Instantiation 
    • 3. Bean Initialization 
    • 4. Bean Destruction

1. Bean Class Loading:

  • When IOC Container recognized fully qualified names of the bean classes in beans configuration file then IOC Container will load the specified bean class byte code to the memory. To load bean class bytecode to the memory, IOC Container will use the following method.
    • public static Class forName(String class_Name)throws ClassNotFoundException 
    •  EX: Class c=Class.forName("com.cloud.beans.WelcomeBean");

2. Bean Instantiation

  • In Spring applications, after loading bean class bytecode to the memory, IOC Container will create object for the bean class.
  • IN Spring applications we are able to use the following three approaches to create Bean objects.
    • 2.1. By using Constructor directly. 
    • 2.2. By Using Static Factory Method 
    • 2.3. By Using Instance Factory Method

2.1. Bean Instantiation through Constructors:

  • If we want to create bean objects by using constructors then we must provide 0-arg costructor in bean class irrespective of bean class constructor scopes.
  • Note: In Bean class , if we provide parameterized constructor then IOC Container will rise an exception.

Example

HelloBean.java

public class HelloBean{
	public HelloBean(){ 
		System.out.println("Bean Instantiation"); 
	}
	public String sayHello(){ 
		System.out.println("Hello User!";
	}
}

applicationContext.xml

<beans>
	<bean id="hello" class="HelloBean"/>
</beans>

Test.java

class Test{
	public static void main(String[] args){
		ApplicationContext context=new 
			ClassPathXmlApplicationContext("applicationContext.xml"); 
		HelloBean bean=(HelloBean)context.getBean("hello"); 
		System.out.println(bean.sayaHello());
	}
}

2.2. Bean Instantiation through Static Factory Method:

  • In this approach, first we have to define static factory method in Bean class and we have to configure that static factory method in bean defination in beans configuration file. 

Example:

HelloBean.java

public class HelloBean{
	public static HelloBean getInstance(){
		System.out.println("Static Factory Method");
		return new HelloBean(); 
	}
	public String sayHello(){ 
		System.out.println("Hello User!"; 
	}
}

applicationContext.xml

<beans>
	<bean id="hello" class="HelloBean" factory-method="getInstance"/>
</beans>

Test.java

class Test{
	public static void main(String[] args){
		ApplicationContext context=new 
			ClassPathXmlApplicationContext("applicationContext.xml"); 
		HelloBean bean=(HelloBean)context.getBean("hello"); 
		System.out.println(bean.sayaHello());
	}
}

2.3 Bean Instantiation through Instance Factory Method:

  • In this approach, we have to define a seperate factory class with instance factory method and we have to configure factory class as bean in beans configuration file then we have to configure factory class and factory method in the original bean class definition by using "factory-bean" and "factory-method" attributes.

Example:

HelloBeanFactory.java

public class HelloBeanFactory{
	public HelloBean getBeanInstance(){ 
		System.out.println("Instance Factory Method"); 
	return new HelloBean();
}

HelloBean.java

public class HelloBean{
	public String sayHello(){ 
		System.out.println("Hello User!"; 
	}
}


applicationContext.xml

<beans>
	<bean id="hello" class="HelloBean" factory-method="getBeanInstance" 
			factory-bean="factory" />
	<bean id="factory" class="HelloBeanFactory"/>
</beans>

Test.java

class Test{
 public static void main(String[] args){
	ApplicationContext context=new 
		ClassPathXmlApplicationContext("applicationContext.xml"); 
	HelloBean bean=(HelloBean)context.getBean("hello"); 
	System.out.println(bean.sayaHello());
 }
}


3. Bean Initialization and Bean Destruction:

  • As part of Beans lifecycle, IOC Container has to perform Beans initialization after the Bean Instantiation and IOC Container has to perform Bean destruction after executing the business logic or at the time of shutdown the IOC Container.
  • There are three ways to perform Beans initialization and destruction in Spring Framework.
    • 3.1. By using Custom initialization and destruction methods.
    • 3.2. By using InitializingBean and DesposableBean callback interfaces. 
    • 3.3. By using @PostConstruct and @Predestroy annotations

3.1. By using Custom initialization and destruction methods:

  • In this approach, we have to define user defined initialization and destruction methods with any name and we have to configure that user defined methods in beans definitions in beans configuration file by using "init-method" and "destroy-method" attributes in <bean> tag.

Example:

WelcomeBean.java

package com.cloud.beans;

public class WelcomeBean {
	public void init(){
		System.out.println("User defined init() method");
	}
	public String sayWelcome(){
		return "Welcome To cloud Software Solutions";
	}
	public void destroy(){
		System.out.println("User defined destroy() Method"); 
	}
}

applicationContext.xml

<beans>
	<bean id="wel" class="com.cloud.beans.WelcomeBean"
			init-method="init" destroy-method="destroy" /> 
</beans>

Test.java

package com.cloud.test;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.WelcomeBean;

public class Test {
	public static void main(String[] args)throws Exception { 
		AbstractApplicationContext context=new 
			ClassPathXmlApplicationContext("applicationContext.xml");
		WelcomeBean bean=(WelcomeBean)context.getBean("wel"); 
		System.out.println(bean.sayWelcome());
		context.registerShutdownHook();
	}

}

3.2. By using InitializingBean and DesposableBean callback interfaces:

  • In Spring framework, InitializingBean is a callback interface , it provides the following method to execute while performing bean initialization by IOC Container.

    • public void afterPropertiesSet()throws Exception

  • Note

    • This method will be executed by the container after executing all the setXXX() methods of bean class by ApplicationContext.

  • In Spring framework, DisposableBean is a callback interface, it provides the following method to execute while performing Bean Destruction by IOC Container.

    • public void destroy()

Example:

WelcomeBean.java

package com.cloud.beans;

import org.springframework.beans.factory.DisposableBean; 
import org.springframework.beans.factory.InitializingBean;

public class WelcomeBean implements InitializingBean,DisposableBean{ 
	private String message;
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) { 
		this.message = message; System.out.println("setMessage()");
	}
	public String sayWelcome(){
		return message;

	}
	@Override
	public void afterPropertiesSet() throws Exception { 
		message="Welcome To cloud Software Solutions"; 
		System.out.println("afterPropertiesSet()");
	}
	@Override
	public void destroy() throws Exception { 
		System.out.println("destroy()");
	}
}

applicationContext.xml

<beans>
	<bean id="wel" class="com.cloud.beans.WelcomeBean">
	<property name="message" value="Welcome To cloud"/>
	</bean> 
</beans>

Test.java

package com.cloud.test;

import org.springframework.context.support.AbstractApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.WelcomeBean;

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

	AbstractApplicationContext context=new 
		ClassPathXmlApplicationContext("applicationContext.xml");
	WelcomeBean bean=(WelcomeBean)context.getBean("wel"); 
	System.out.println(bean.sayWelcome());
	context.registerShutdownHook();
 }
}

3.3. By using @PostConstruct and @Predestroy annotations

  • @PostConstruct annotation will make a method to execute by the IOC Container while performing Beans iniitalization.
  • @Predestroy annotation will make a method to execute by the IOC Container while performing Bean Destruction.

Example:

Welcome.java

package com.cloud.beans;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

	public class WelcomeBean { 
		private String message;
	}

	public String getMessage() { 
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
		System.out.println("setMessage()"); 
	}

	public String sayWelcome(){ 
		return message;
	}	
	
	@PostConstruct public void init(){
		System.out.println("postConstruct method"); 
	}

	@PreDestroy
	public void destroy(){
		System.out.println("preDestroy method"); 
	}
}

applicationContext.xml

<beans>
	<context:annotation-config/>
	<bean id="wel" class="com.cloud.beans.WelcomeBean">
		<property name="message" value="Welcome To cloud"/> 
	</bean>
</beans>

Note

  • We need to provide "context" name space along with beans name space in spring beans configuration file.

Test.java

public class Test {
	public static void main(String[] args)throws Exception { 
		AbstractApplicationContext context=new 
			ClassPathXmlApplicationContext("applicationContext.xml"); 

		WelcomeBean bean=(WelcomeBean)context.getBean("wel"); 
		System.out.println(bean.sayWelcome()); 
		context.registerShutdownHook();
	}
}

Note

  • In general, in spring framework applications, we are able to use either of the above three approaches to performing beans initialization and destruction, we are not using all three approaches at a time. 
  • If we use all the above three approaches in single bean theni IOC Container will execute the above three approaches provided intialization methods and destruction methods in the following order.

  • Initialiazation order:

    • 1. An initialization method marked with @Postconstruct annotation.
    • 2.afterPropertiesSet() method provided by InnitializingBean callback interface.
    • 3. AN initialization method configured with "init-method" in <bean> tag in configuration file

  • Destruction Order:

    • 1. A Destruction method marked with @Predestroy annotation
    • 2. destroy() method provided by DisposableBean callback interface.
    • 3. A destruction method configured with "destroy-method" annotation in beans configuration file.

  •  If we have same initialization method and destruction method in more than one bean class in spring application then we are able to provide common init method and destroy method configuration by using "default-init-method" attribute and "default-destroy-method" attribute in <beans> tag[not in <bean> tag] with out providing "init-method" and "destroy-method" attributes in <bean> tag at each and every bean configuration.

Example:

Welcome.java

public class Welcome {
	public void init(){ 
		System.out.println("init()-Welcome");
	}
	public void destroy(){ 
		System.out.println("destroy()-Welcome"); }		
	}
}

Hello.java

public class Hello{
	public void init(){ 
		System.out.println("init()-Hello");
}

spring_beans_config.xml

<beans default-init-method="init" default-destroy-method="destroy"> 
	<bean id="welcome" class="com.cloud.beans.Welcome"/>
	<bean id="hello" class="com.cloud.beans.Hello"/> 
</beans>

Test.java

public class Test{
	public static void main(String[] args){
		AbstractApplicationContext context=new 
			ClassPathXmlApplicationContext(" /com/cloud/cfgs/spring_beans_config.xml");
		Welcome bean1=(Welcome)context.getBean("welcome");
		Hello bean2=(Hello)context.getBean("hello"); 
		context.registerShutdownHook();
	}
}
Bean Inheritance

  • In general, in Spring framework, we are able to provide more and more no of configuration details in beans definitions under beans configuration file like properties configurations, dependency injection related configurations, initialization destruction methods configurations,.......
  • In the above context, we are able to reuse one bean configuration details in another bean configurations like normal java classes inheritance inorder to improve reusability and inorder to reduce no of configurations in spring configuration file by declaring parent and chaild beans configurations.
  • To declare a particular bean configuration as parent to the present bean configuration then we have to use "parent" attribute in "<bean>" tag in beans configuration file, where "parent" attribute will take identity of the respective bean definition.

Example: 

WishBean.java

package com.cloud.beans;
public class WishBean 
	private String wish_Message; private String name;
	public void init(){
		System.out.println("WishBean Initialization");
	}	

	public void destroy(){
		System.out.println("WishBean Destruction"); 
	}
	setXXX() 
	getXXX()
}


HelloBean.java

package com.cloud.beans; 

public class HelloBean {

	private String wish_Message; private String name;
	public void init(){
		System.out.println("HelloBean Initialization");
	}

	public void destroy(){
		System.out.println("HelloBean Destruction"); 
	}

	setXXX() 
	getXXX()

	public String sayHello(){
		return wish_Message+name;
	} 
}

WelcomeBean.java

package com.cloud.beans; 
public class WelcomeBean {
	private String wish_Message; private String name;
	public void init(){ 
		System.out.println("WelcomeBean Initialization"); 
	}

	public void destroy(){
		System.out.println("WelcomeBean Destruction"); 
	}
	setXXX() 
	getXXX()
	public String sayWelcome(){
		return wish_Message+name;
	} 
}

spring_beans_config.xml

<beans>
	<bean id="wishBean" class="com.cloud.beans.WishBean" 
		init-method="init"destroy-method="destroy">
		<property name="wish_Message" value="cloud Software Solutions"/> 
		<property name="name" value="Anil"/>
	</bean>

	<bean id="helloBean" class="com.cloud.beans.HelloBean" parent="wishBean">
		<property name="wish_Message" value="Hello "/> 
	</bean>
	<bean id="welcomeBean" class="com.cloud.beans.WelcomeBean" parent="wishBean">
		<property name="wish_Message" value="Welcome "/> 
	</bean>
</beans>

Test.java

package com.cloud.test;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.HelloBean;
import com.cloud.beans.WelcomeBean;

public class Test {

 public static void main(String[] args)throws Exception {

	AbstractApplicationContext context=new 
		ClassPathXmlApplicationContext("/com/cloud/cfgs/ spring_beans_config.xml"); 
	
	HelloBean hello=(HelloBean)context.getBean("helloBean"); 
	System.out.println(hello.sayHello());
	System.out.println();

	WelcomeBean welcome=(WelcomeBean)context.getBean("welcomeBean"); 
	System.out.println(welcome.sayWelcome());
	context.registerShutdownHook();
 }

}

  • In the above Beans Inheritance, it is possible to declare parent bean definition as a template, that is, a set of configurations which we want to apply to chaild definintions, not to have its own bean class and not to apply to its own bean class.
  • To declare a bean definition as template we have to use "abstract" attribute with "true" value in <bean> tag , in this context, it is not required to use "class" attribute in bean tag.

Example:

<beans>
	<bean id="wishBean" abstract="true" .... >
	</bean>
	<bean id="helloBean" class="HelloBean" parent="wishBean">
	</bean>
	<bean id="welBean" class="WelcomeBean" parent="wishBean">
	</bean> 
</beans>

WishBean.java

	<bean id="wishBean" class="com.cloud.beans.WishBean" 
		init-method="init"destroy-method="destroy">
		<property name="wish_Message" value="cloud Software Solutions"/> 
		<property name="name" value="Anil"/>
	</bean>

	<bean id="helloBean" class="com.cloud.beans.HelloBean" parent="wishBean">
		<property name="wish_Message" value="Hello "/> 
	</bean>
	<bean id="welcomeBean" class="com.cloud.beans.WelcomeBean" parent="wishBean">
		<property name="wish_Message" value="Welcome "/> 
	</bean>
</beans>

HelloBean.java

package com.cloud.beans;
public class WishBean {
	private String wish_Message; private String name;
	public void init(){
		System.out.println("WishBean Initialization");
	}
	
	public void destroy(){
		System.out.println("WishBean Destruction"); 
	}
	
	public String getWish_Message() { 
		return wish_Message;
	}

	public void setWish_Message(String wish_Message) {
		this.wish_Message = wish_Message; 
	}
	public String getName() { 
		return name;
	}

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

WelcomeBean.java

package com.cloud.beans;
public class WishBean {
	private String wish_Message; 
	private String name;
	
	public void init(){
		System.out.println("WishBean Initialization");
	}
	
	public void destroy(){
		System.out.println("WishBean Destruction"); 
	}
	
	public String getWish_Message() { 
		return wish_Message;
	}

	public void setWish_Message(String wish_Message) {
		this.wish_Message = wish_Message; 
	}
	public String getName() { 
		return name;
	}

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

Test.java

package com.cloud.test;

import org.springframework.context.support.AbstractApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.HelloBean;
import com.cloud.beans.WelcomeBean;
import com.cloud.beans.WishBean;

public class Test {

	public static void main(String[] args)throws Exception { 
		AbstractApplicationContext context=new 
			ClassPathXmlApplicationContext("applicationContext.xml");

		//WishBean wish = (WishBean)context.getBean("wishBean");
				---> Exception //System.out.println(wish);

		HelloBean hello=(HelloBean)context.getBean("helloBean"); System.out.println(hello.sayHello());
		System.out.println();

		WelcomeBean welcome=(WelcomeBean)context.getBean("welcomeBean"); 
		System.out.println(welcome.sayWelcome()); context.registerShutdownHook();
	}
}

applicationContext.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">

	<bean id="wishBean" abstract="true" init-method="init" 
		destroy-method="destroy"> <property name="wish_Message" value="cloud Software Solutions"/>
		<property name="name" value="Anil"/>
	</bean>
	<bean id="helloBean" class="com.cloud.beans.HelloBean" parent="wishBean">
		<property name="wish_Message" value="Hello "/> 
	</bean>
	<bean id="welcomeBean" class="com.cloud.beans.WelcomeBean" parent="wishBean">
		<property name="wish_Message" value="Welcome "/> 
	</bean>
</beans>

Nested Beans:

  • Declaring a bean configuration in another bean configuration is called as Inner Beans or Nested Beans.
  • IN Bean class, if we declare any property of User defined class type then we have to use <bean> tag for the user defined class as value to the respective property under <property> tag.

Account.java

package com.cloud.beans; 
public class Account {
    private String accNo; private String accName; 
    private String accType; private long balance;
    setXXX()
    getXXX() 
}

Employee.java

package com.cloud.beans; 

public class Employee {
    private String eid; 
    private String ename; 
    private float esal; 
    private String eaddr; 
    private Account acc;

    setXXX() 
    getXXX()

    public void displayEmpDetails(){
        System.out.println("Employee Details"); 
        System.out.println("-----------------------"); 
        System.out.println("Employee Id :"+eid); 
        System.out.println("EmployeeName :"+ename); 
        System.out.println("Employee Salary :"+esal); 
        System.out.println("Employee Address:"+eaddr); 
        System.out.println();
        System.out.println("Account Details"); 
        System.out.println("---------------------"); 
        System.out.println("Account Number :"+acc.getAccNo()); 
        System.out.println("Account Name :"+acc.getAccName()); 
        System.out.println("Account Type :"+acc.getAccType()); 
        System.out.println("Account Balance :"+acc.getBalance());
    } 
}

  applicationContext.xml

<beans>
    <bean id="emp" class="com.cloud.beans.Employee">
        <property name="eid" value="E-111"/> 
        <property name="ename" value="cloud"/> 
        <property name="esal" value="10000"/> 
        <property name="eaddr" value="Hyd"/> 
        <property name="acc">
            <bean id="account" class="com.cloud.beans.Account"> 
              <property name="accNo" value="abc123"/> 
              <property name="accName" value="cloud"/> 
              <property name="accType" value="Savings"/> 
              <property name="balance" value="20000"/>
            </bean> 
        </property>
    </bean> 
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cloud.beans.Employee;

public class Test {
    public static void main(String[] args)throws Exception {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Employee emp=(Employee)context.getBean("emp");
        emp.displayEmpDetails();

    }
}
BeanPost Processor

  • In Spring Framework, when we activate ApplicationContext container then ApplicationContext container will perform the following actions automatically with out having developers interaction.

    • 1. ApplicatinContext will read beans definitions from beans configuration file.
    • 2. ApplicationContext will recognize beans classes and creates objecs for bean classes 
    • 3. ApplicationContext will perform initialization by executing initialization methods. 
    • 4. When IOCContainer is shutdown then bean objects are destroyed.

  • In the above Bean lifecycle, if we want to provide customizations over beans initializations then we have to use a predefined interface provided by Spring framework like"org.springframework.beans.factory.config.BeanPostProcessor".
  • BeanPostProcessor contains the following two methods .

    • 1.public void postProcessBeforeInitialization(Object bean, String name) throws BeansException
      • This method will be executed just before performing bean initialization andimmediatly after bean instantiation, that is, before executing init() method if we provide custom initialization method init().

    • 2. public void postProcessAfterInitialization(Object bean, String name) throws BeansException
      • This method will be executed immediatly after performing beans initialization, that is, after executing init() method if we provide custom initialization method init().

  • To use BeanPostPrcessor in Spring applications we have to declare an user defined class as an implementation class to BeanPostProcessor interface , we must implement the above specified methods and we must configure implementation class in bean configuration file. 
  • If we provide like this then container will detect BeanPostProcessor implementation automatically and IOCContainer will execute the BeanPostProcessor methods in the respective locations of the beans lifecycle.

Example:

BeanPostProcessorImpl.java

package com.cloud.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.cloud.beans.Customer;

public class BeanPostProcessorImpl implements BeanPostProcessor { 

    @Override
    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
        System.out.println("postProcessAfterInitialization()");
        Customer cust=(Customer)bean;
        cust.setCmobile("91-9988776655");
        return cust;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        System.out.println("postProcessBeforeInitialization()");
        Customer cust=(Customer)bean;
        cust.setCemail("cloud@cloud.com"); return cust;
    }
}

Customer.java

package com.cloud.beans; 

public class Customer {
  private String cid; 
  private String cname; 
  private String caddr; 
  private String cemail; 
  private String cmobile;

  public Customer(){
    System.out.println("Customer Bean Object Creating");
  }

  public void init(){
    System.out.println("Customer Bean Object Initialization through init() method");
  }

  public void destroy(){
    System.out.println("Customer Object Destroying through destroy() method");
  }

  setXXX()
  getXXX()

  public void getCustomerDetails(){
    System.out.println("Customer Details"); 
    System.out.println("---------------------"); 
    System.out.println("Customer Id :"+cid); 
    System.out.println("CustomerName :"+cname); 
    System.out.println("Customer Address:"+caddr); 
    System.out.println("Customer Email :"+cemail); 
    System.out.println("Customer Mobile :"+cmobile);
  } 
}

 applicationContext.xml

<beans>
  <bean id="cust" class="com.cloud.beans.Customer" 
      init-method="init" method="destroy">
  <property name="cid" value="C-111"/>
  <property name="cname" value="cloud"/>
  <property name="caddr" value="Hyd"/> 
  </bean>
  <bean class="com.cloud.processor.BeanPostProcessorImpl"/> 
</beans>

Test.java

package com.cloud.test;
import org.springframework.context.support.AbstractApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import com.cloud.beans.Customer;

public class Test {
  public static void main(String[] args)throws Exception { 
    AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

    Customer cust=(Customer)context.getBean("cust");
    cust.getCustomerDetails();
    context.registerShutdownHook();
  }
}

You may also like

Kubernetes Microservices
Python AI/ML
Spring Framework Spring Boot
Core Java Java Coding Question
Maven AWS