Thursday, June 3, 2021

ApplicationContextAware And BeanNameAware Interfaces in Spring Framework

In this post we'll learn about two "aware" interfaces; ApplicationContextAware and BeanNameAware in Spring.

ApplicationContextAware interface in Spring

If a class implements org.springframework.context.ApplicationContextAware interface, then the object instance of that class is provided with a reference to the ApplicationContext that it runs in.

ApplicationContextAware interface has a single method setApplicationContext with ApplicationContext as parameter.

ApplicationContextAware interface

public interface ApplicationContextAware {
   void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

By implementing the ApplicationContextAware interface a bean has access to the Spring's ApplicationContext so beans can manipulate programmatically the ApplicationContext that created them. Primary use of it is the programmatic retrieval of other beans using the application context.

Though Spring docs cautions against using ApplicationContextAware- "however, in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties."

Usage of ApplicationContextAware interface

Though not used that extensively but two scenarios where I think ApplicationContextAware interface is of use are-

  1. You can use it as one of the way to inject prototype scoped bean in a singleton bean.
  2. When you want to access Spring bean from some other code which is not with in the Spring container.

Using ApplicationContextAware to inject prototype scoped bean in a singleton bean

Let’s say we have two classes RequestManager and RequestHandler where RequestHandler class bean scope is prototype and bean scope for RequestManager is singleton. RequestManager has a dependency on RequestHandler, since the scope for RequestHandler is prototype you would want to have a new instance of RequestHandler rather than the same instance being used with in the Spring container.

RequestManager class can implement ApplicationContextAware interface and get an instance of RequestHandler through the reference of ApplicationContext.

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class RequestManager implements ApplicationContextAware{
 private RequestHandler requestHandler;
 private ApplicationContext applicationContext;
 
 public void handleRequest(){
   requestHandler = getRequestHandler();
   requestHandler.handleRequest();
 }
 // method to return new instance
 public RequestHandler getRequestHandler() {
   return applicationContext.getBean("requestHandler", RequestHandler.class);
 }
 public void setRequestHandler(RequestHandler requestHandler) {
  this.requestHandler = requestHandler;
 }
 @Override
 public void setApplicationContext(ApplicationContext applicationContext)
   throws BeansException {
  this.applicationContext = applicationContext; 
  
 } 
}

See the full example here- How to Inject Prototype Scoped Bean in Singleton Bean

Using ApplicationContextAware to access Spring bean from other code

Another scenario where ApplicationContextAware interface can be used is when you want to access Spring beans from some code which is not yet converted to Spring.

For that you can create a class implementing ApplicationContextAware interface and define it in your configuration so that it is instantiated by the Spring container. Now this class can act as a bridge between the spring beans and the code that is outside Spring environment.

Class implementing ApplicationContextAware interface

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ProjApplicationContext implements ApplicationContextAware{
 private static ApplicationContext appContext;

 @Override
 public void setApplicationContext(ApplicationContext applicationContext)
   throws BeansException {
  appContext = applicationContext;
  
 }
 
 public static Object getBean(String beanName){
  return appContext.getBean(beanName);
 }
}

XML Configuration

<bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
<bean id="cardPaymentBean" class="org.netjs.exp.Spring_Example.CardPayment" />
<bean id="projApplicationContext" class="org.netjs.exp.Spring_Example.ProjApplicationContext"/>

Now, if you want to call a method of cashPaymentBean from other code which is not part of Spring. In the class AppDemo which is not in Spring container Spring bean is retrieved by calling the static getBean() method of the ProjApplicationContext class which in turn gets the bean from the ApplicationContext.

public class AppDemo {
 
 public void performTask(){
  CashPayment cashPayment = (CashPayment)ProjApplicationContext.getBean("cashPaymentBean");
  cashPayment.executePayment();
 }
}

Since I am running this code as a simple Java application so creating object of AppDemo where context is created otherwise context will get closed.

public class App {
  public static void main( String[] args ){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    AppDemo appDemo = new AppDemo();
    appDemo.performTask();
    context.registerShutdownHook();  
  }
}

BeanNameAware Interface in Spring

A class implementing org.springframework.beans.factory.BeanNameAware interface can get its name defined in its associated object definition.

BeanNameAware interface has a single method setBeanName(String name).

public interface BeanNameAware {
  void setBeanName(String name) throws BeansException;
}

The callback is invoked after population of normal bean properties but before an initialization callback such as InitializingBean afterPropertiesSet or a custom init-method.

Usage of BeanNameAware interface

Though Spring framework uses BeanNameAware interface internally but in user defined beans it doesn’t have much practical use. Only use I have seen is it is helpful when logging.

Class implementing BeanNameAware interface

import org.springframework.beans.factory.BeanNameAware;

public class CashPayment implements BeanNameAware{
 private String name;
 
 public void executePayment() {
  System.out.println("Perform Payment using " + name); 
 }
 
 @Override
 public void setBeanName(String name) {
  this.name = name;
 }
}

Configuration for the class bean

<bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
Running the code
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
  public static void main( String[] args ){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");

    CashPayment cashPayment = (CashPayment)context.getBean("cashPaymentBean");
    cashPayment.executePayment();
    context.registerShutdownHook();
  }   
}

Output

Perform Payment using cashPaymentBean

That's all for this topic ApplicationContextAware And BeanNameAware Interfaces in Spring Framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Bean Definition Inheritance in Spring
  2. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation
  3. Injecting Inner Bean in Spring
  4. Circular Dependency in Spring Framework
  5. Spring Profiles With Examples

You may also like-

  1. Wiring Collections in Spring
  2. Spring NamedParameterJdbcTemplate Select Query Example
  3. How to Inject Null And Empty String Values in Spring
  4. How HashSet Works Internally in Java
  5. Just In Time Compiler (JIT) in Java
  6. Java Stream API Examples
  7. instanceof Operator in Java With Examples
  8. What is SafeMode in Hadoop

No comments:

Post a Comment