Making Beans Aware of the Container

Problem

A well-designed component should not have direct dependencies on its container. However, sometimes it’s necessary for your beans to be aware of the container’s resources.

Solution

Your beans can be aware of the Spring IoC container’s resources by implementing certain “aware” interfaces, as shown in Table 4-2. Spring will inject the corresponding resources to your beans via the setter methods defined in these interfaces.

Aware Interface Target Resource
BeanNameAware The bean name of its instances configured in the IoC container
BeanFactoryAware The current bean factory, through which you can invoke the container’s services
ApplicationContextAware* The current application context, through which you can invoke the container’s services
MessageSourceAware A message source, through which you can resolve text messages
ApplicationEventPublisherAware An application event publisher, through which you can publish application events
ResourceLoaderAware A resource loader, through which you can load external resources

* In fact, the ApplicationContext interface extends the MessageSource, ApplicationEventPublisher, and ResourceLoader interfaces, so you only need to be aware of the application context to access all these services.However, the best practice is to choose an aware interface with minimum scope that can satisfy your requirement.

The setter methods in the aware interfaces will be called by Spring after the bean properties have been set, but before the initialization callback methods are called, as illustrated in the following list:

1. Create the bean instance either by a constructor or by a factory method.

2. Set the values and bean references to the bean properties.

3. Call the setter methods defined in the aware interfaces.

4. Call the initialization callback methods.

5. The bean is ready to be used.

6. When the container is shut down, call the destruction callback methods.

Keep in mind that once your beans implement the aware interfaces, they are bound to Spring and may not work properly outside the Spring IoC container. You must consider carefully whether it’s necessary to implement such proprietary interfaces.

How It Works

For example, you can make your cashier bean aware of its bean name in the IoC container by implementing the BeanNameAware interface. When this bean name is injected, you can save it as the cashier name. This can save you the trouble of setting another name property for the cashier.

package com.shop;
import org.springframework.beans.factory.BeanNameAware;
public class Cashier implements BeanNameAware {
public void setBeanName(String beanName) {
this.name = beanName;
}
}

You can simplify your cashier bean declaration by using the bean name as the cashier name. In this way, you can erase the configuration of the name property and perhaps the setName() method as well.

<bean id="cashier1" class="com.shop.Cashier">
<property name="path" value="c:/cashier" />
</bean>

Note: remember that you can specify the field name and the property path as the bean names of FieldRetrievingFactoryBean and PropertyPathFactoryBean directly? In fact, both factory beans implement the BeanNameAware interface.