Learnitweb

Spring @Bean annotation

1. Introduction

In this tutorial, we’ll discuss @Bean annotation which is a very important annotation to know.

A Java object instance managed by Spring container is called bean. This annotation is typically used to define methods to create beans.

You can use the @Bean annotation in a @Configuration-annotated or in a @Component-annotated class. A method annotated with @Bean registers a bean definition within an ApplicationContext of the type specified as the method’s return value.

Following is the declaration of @Bean annotation:

@Target(value={METHOD,ANNOTATION_TYPE})
@Retention(value=RUNTIME)
@Documented
public @interface Bean

@Bean is a method-level annotation and a direct analog of the XML <bean/> element. This annotation is used on a method and indicates that the method produces a bean to be managed by the Spring container. Following is a typical example of using @Bean annotation:

@Bean
public MyBean myBean() {
    // instantiate and configure MyBean obj
    return obj;
} 

@Bean annotation does not provide attributes for profile, scope, lazy, depends-on or primary. If you need these then @Scope, @Lazy, @DependsOn and @Primary annotations are available separately. For example:

@Bean
@Profile("production")
@Scope("prototype")
public MyBean myBean() {
	// instantiate and configure MyBean obj
    return obj;
}

The annotation supports some of the attributes offered by <bean/>, such as:

  • init-method
  • destroy-method
  • autowiring
  • name

2. Bean names

By default the name of the bean is the name of the method. However, the @Bean annotation provides a name() attribute. The name() attribute can be used to provide name and alias explicitly for the bean. The name() attribute accepts an array of Strings, i.e. a primary bean name plus one or more aliases for a single bean.

@Bean({"name1", "alias1"}) // Both 'name1' and 'alias1' are valid names for bean
public MyBean myBean() {
	// instantiate and configure MyBean obj
	return obj;
}

3. @Bean Methods in @Configuration Classes

Typically, @Bean methods are declared within @Configuration classes. One @Bean method can call another @Bean method. These method calls are called as ‘inter-bean references‘.

 @Configuration
 public class AppConfig {

     @Bean
     public MyService myService() {
         return new MyService(myRepository());
     }

     @Bean
     public MyRepository myRepository() {
         return new JdbcMyRepository(dataSource());
     }

     // ...
 }

4. @Bean with default methods

You can use default methods to define beans. This allows composition of bean configurations by implementing interfaces with bean definitions on default methods.

public interface BaseConfig {

	@Bean
	default MyServiceImpl myService() {
		return new MyServiceImpl();
	}
}

@Configuration
public class AppConfig implements BaseConfig {

}

5. @Bean Lite Mode

Typically, @Bean methods are declared in @Configuration classes. However, it is not mandatory. Bean methods may be declared even in a plain old class or a class not declared with @Configuration such as @Component. In such cases, a @Bean method will get processed in a so-called ‘lite‘ mode. Bean methods in lite mode will be treated as plain factory methods by the container (similar to factory-method declarations in XML), with scoping and lifecycle callbacks properly applied. The ‘inter-bean references’ are not supported in lite mode.

6. Bean Dependencies

A method annotated with @Bean can accept any number of parameters, each representing a dependency needed to create that bean.

For instance, if our MyService requires an SomeDependencyRepository, we can materialize that dependency with a method parameter, as the following example shows:

@Configuration
public class AppConfig {

	@Bean
	public MyService myService(SomeDependencyRepository someDependencyRepository) {
		return new MyServiceImpl(someDependencyRepository);
	}
}

The resolution mechanism is pretty much identical to constructor-based dependency injection.

7. BeanFactoryPostProcessor-returning @Bean methods

@Bean method which return BeanFactoryPostProcessor types should be declared as static. This is because these methods should be instantiated very early in the container lifecycle else these can create lifecycle issues. By marking this method as static, such methods can be invoked without causing instantiation of its declaring @Configuration class, thus avoiding the above-mentioned lifecycle conflicts.

8. Lifecycle Callbacks

Any classes defined with the @Bean annotation support the regular lifecycle callbacks and can use the @PostConstruct and @PreDestroy annotations from JSR-250.

The standard Spring lifecycle callbacks are also fully supported. If a bean implements InitializingBean, DisposableBean, or Lifecycle, the container will invoke their corresponding methods.

The standard set of *Aware interfaces (such as BeanFactoryAware, BeanNameAware, ApplicationContextAware, MessageSourceAware and so on) are also fully supported.

public class BeanOne {

	public void init() {
		// initialization logic
	}
}

public class BeanTwo {

	public void cleanup() {
		// destruction logic
	}
}

@Configuration
public class AppConfig {

	@Bean(initMethod = "init")
	public BeanOne beanOne() {
		return new BeanOne();
	}

	@Bean(destroyMethod = "cleanup")
	public BeanTwo beanTwo() {
		return new BeanTwo();
	}
}

9. @Scope with @Bean

You can specify that your beans defined with the @Bean annotation should have a specific scope.

@Configuration
public class MyConfiguration {

	@Bean
	@Scope("prototype")
	public MyService myService() {
		// ...
	}
}

10. Bean Description

To add a description to a @Bean, you can use the @Description annotation. Here is an example:

@Configuration
public class AppConfig {

	@Bean
	@Description("Provides a basic example of a bean")
	public MyService myService() {
		return new MyService();
	}
}

11. Conclusion

In conclusion, the @Bean annotation in Spring is a powerful tool for defining and managing beans within a Spring application context. By using this annotation, developers can specify the beans that should be managed by the Spring container, along with their dependencies, lifecycle callbacks, and other configurations. Understanding how to effectively utilize the @Bean annotation allows for more flexible and maintainable code, leveraging Spring’s comprehensive dependency injection capabilities to build robust and scalable applications.