Bean is one of the angular stones in the Spring Framework and it is very important to know how it works. However, the concept of bean it is not very clear and the Bean definition given by the official Spring documentation is not easy to understand.
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
Roughly, we can say that a Bean is simply an object with a concrete life cycle managed by the Spring Framework.
This definition might seem a little bit abstract, but do not worry we will go into more in depth shortly.
Moreover, we will answer some frequent Spring interview questions like:
- Explain IoC in Spring Framework?
- Explain Dependency Injection in Spring?
- What are different Bean scopes in Spring?
- Can you explain Bean life cycle in Spring Bean Factory Container?
Concepts
Spring IoC
According to the Spring definition of Bean, this special object is managed by the Spring IoC container, which is represented in your application by org.springframework.context.ApplicationContext
, and this container is responsible for the initialization, configuration and assembly. But we will not have to worry about enriching (add metadata) the bean, since it is done by the framework by using XML config files, annotations or Java code.
A Spring IoC container can manage one or more beans and once all the beans are loaded in this container, you can retrieve instances of your beans through the ApplicationContext
(getBean()
).
Dependency Injection
The definition of DI given by Spring is very straightforward, and simply says that DI is the process of defining objects with their dependencies, that are set on the object instance through a constructor or setters.
DI is used by the IoC container, which injects the dependencies when the bean is created. Therefore, it is not the bean, it is the container the one responsible for injecting the dependencies. The Bean does not need to know anything about the instantiation and location of the dependencies, and that is why it is called Inversion of Control.
Bean Scopes
All the beans are not the same, and Spring provides a few different recipes to modify the scope. In total there are six scopes:
- singleton (default): creates one instance for each IoC container (
ApplicationContext
). - prototype: a new instance is created every time the bean is called.
- request: creates a single instance per HTTP request.
- session: one instance for each web session.
- application: only one instance per
ServletContext
. - websocket: it is tight to the websocket lifecycle.
Do not confuse Bean with scope singleton with the Singleton Design Pattern. The latter creates an instance per
ClassLoader
, whereas the singleton Bean creates a bean per Spring container.
When using singleton Bean which contains beans with different lifecycles, remember that injection only happens once. We can use beans with different scopes by using
proxyMode = ScopedProxyMode.TARGET_CLASS
in the@Scope
annotation.
Lifecycle
Spring Bean Creation Lifecycle
- Instantiate Bean
- Spring IoC container add metadata to the bean
- If
BeanNameAware
is implemented, Spring will set the name pass as parameter insetBeanName()
. - If
BeanFactoryAware
is implemented, Spring will callsetBeanFactory()
. - If
ApplicationContextAware
is implemented, Spring will pass a reference to theApplicationContext
insetApplicationContext()
method. - If
BeanPostProcessor
is implemented, it will runProcessBeforeInitialization()
method. - If
@PostConstruct
is used,InitializingBean
is implemented, orinit()
is implicitly called, Spring callsafterPropertiesSet()
method. - If
BeanPostProcessor
is implemented, Spring will runpostProcessAfterInitialization()
method. - The bean now can be used and remains in the application context until it is destroyed.
Spring Bean Destruction Lifecycle
- Spring IoC container is shutdown.
- If
@PreDestroy
is used,DisposableBean
is implemented, ordestroy()
method is implicitly called, Spring will rundestroy()
method.
Lifecycle Callbacks
Spring recommend us to use @PostConstruct
and @PreDestroy
annotations to perform work during bean initialization and bean destruction.
In case of XML configuration we can use the init-method or destroy-method attributes.
In the following Bean declaration we are combining Lifecycle mechanisms, and they will be called in a particular order.
@Component
public class ExampleBean implements InitializingBean, DisposableBean {
@PostConstruct
public void callbackInitMethod() {
System.out.println("Call init method from Annotation");
}
@PreDestroy
public void callbackDestroyMethod() {
System.out.println("Call destroy method from Annotation");
}
// Not recommended! It couples the code to Spring.
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Call init method from afterPropertiesSet");
}
// Not recommended! It couples the code to Spring.
@Override
public void destroy() throws Exception {
System.out.println("Call destroy method from destroy implementation");
}
}
When running the application we can see when these methods are called.
2019-04-16 18:07:16.638 INFO 25181 --- [ main] c.s.s.SpringBeanLifecycleApplication : Starting SpringBeanLifecycleApplication on LONC02WW2Q9JG5L with PID 25181
2019-04-16 18:07:16.640 INFO 25181 --- [ main] c.s.s.SpringBeanLifecycleApplication : No active profile set, falling back to default profiles: default
Call init method from Annotation
Call init method from afterPropertiesSet
2019-04-16 18:07:16.925 INFO 25181 --- [ main] c.s.s.SpringBeanLifecycleApplication : Started SpringBeanLifecycleApplication in 0.453 seconds (JVM running for 0.845)
Call destroy method from Annotation
Call destroy method from destroy
As we showed before, annotations are executed first and then, overridden methods.
Spring also provides startup and shutdown callbacks and we can use them by just implementing the Lifecycle
interface. Additionally, we can implement LifecycleProcessor
to react when the context changes (onRefresh()
, onClose()
). In case we need a fine-grained control over the startup of a bean we can implement SmartLifecycle
, so we can specify when the bean should start and stop. The default value returned by getPhase()
is 2147483647
(Integer.MAX_VALUE
), which means last to start and first to stop. If getPhase()
method is overriden, and returns Integer.MIN_VALUE
, the Bean will be among the first to start and the last to stop.
@Component
public class ExampleBean implements Lifecycle, LifecycleProcessor, SmartLifecycle {
@Override
public void start() {
System.out.println("Bean is starting");
}
@Override
public void stop() {
System.out.println("Bean is stopping");
}
@Override
public boolean isRunning() {
return false;
}
@Override
public void onRefresh() {
System.out.println("Context is refreshed");
}
@Override
public void onClose() {
System.out.println("Context is closed");
}
@Override
public int getPhase() {
return Integer.MIN_VALUE;
}
}
Finally, Spring also provides a wide range of Aware Interfaces that let you indicate extra work that needs to be done during the Bean lifecycle. The most important Aware interfaces are: ApplicationContextAware
, ApplicationEventPublisherAware
, BeanClassLoaderAware
, BeanFactoryAware
, BeanNameAware
, BootstrapContextAware
, LoadTimeWeaverAware
, MessageSourceAware
, NotificationPublisherAware
, ResourceLoaderAware
, ServletConfigAware
, ServletContextAware
.
Further documentation about Spring Lifecycle is available at the official site.