Search code examples
javaspring

Spring bean creation lifecycle : Why having multiple interaction points?


I'm learning spring and I'm stuck with the bean lifecycle!

When creating a bean, Spring provides several ways to interact with it. We can use one or more of the following:

  • BeanFactoryPostProcessor
  • BeanPostProcessor#postProcessBeforeInitialization
  • @PostConstruct
  • InitializingBean#afterPropertiesSet
  • @Bean#initMethod
  • BeanPostProcessor#postProcessAfterInitialization

Spring calls them in the order above

My question is: Why all these points of interaction? and when to use each of them (the use case)?


Solution

  • A BeanFactoryPostProcessor and a BeanPostProcessor are quite different beast and also apply to different things.

    A BeanFactoryPostProcessor will operate on the metadata for a bean (I like to call it the recipe) and will post process that. A well know example is the PropertySourcesPlaceholderConfigurer which will inject/replace all @Value in configuration with the value. A BeanFactoryPostProcessor operates on the metadata and thus before any bean has been created.

    The BeanPostProcessor can be applied to a bean and can even replace a bean. Spring AOP uses this quite a lot. An example is the PersistenceExceptionTranslationPostProcessor, when a bean has been created it will pass through this BeanPostProcessor and when it is annotated with @Persistence the bean will be replaced by a proxy. This proxy adds exception translation (i.e. it will convert JpaException and SQLException to the Spring DataAccessException). This is done in a BeanPostProcessor. And can be be done before the init-callbacks are called (the postProcessBeforeInitializationor after they have been called thepostProcessAfterInitialization). The PersistenceExceptionTranslationPostProcessorwill run in thepostProcessAfterInitialization` as it needs to be certain the bean has been initialized.

    The ServletContextAwareProcessor will run right after the object has been created to inject the ServletContext as early as possible as the initializing of a bean might depend on it.

    The 3 callbacks for initializing a bean are more or less the same but are called in sequence because they have been included in later versions. It starter with only an interface InitializingBean and init-method in xml (later also added to @Bean and the annotation support was added when annotations became a thing.

    You need init methods to initialize a bean, you might want to check if all properties have been set (like a required datasource) or you might want to start something. A DataSource (especially a connection pool) is a good example to initialize. After all dependencies have been injected you want to start the pool so it will open the connections. Now as you probably cannot modify the code you want to use the init-method if you control the code you probably want to add @PostConstruct. If you are writing an framework that depends on Spring I would use the InitializingBean.

    Next to those 3 init methods you also have the destruction counter-parts. The DisposableBean interface (and destroy-method) and the @PreDestroy annotation. Again when you stop your application you also want to close the connections in your connection pool and you want to probably call the close method on the DataSource. A perfect sample of a destruction callback.