Basic Concepts: @Bean and @Configuration

The central artifacts in Spring’s Java configuration support are @Configuration-annotated classes and @Bean-annotated methods.

The @Bean annotation is used to indicate that a method instantiates, configures, and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring’s <beans/> XML configuration, the @Bean annotation plays the same role as the <bean/> element. You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.

Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class. The simplest possible @Configuration class reads as follows:

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public MyServiceImpl myService() {
		return new MyServiceImpl();
	}
}
@Configuration
class AppConfig {

	@Bean
	fun myService(): MyServiceImpl {
		return MyServiceImpl()
	}
}

The preceding AppConfig class is equivalent to the following Spring <beans/> XML:

<beans>
	<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
@Configuration classes with or without local calls between @Bean methods?

In common scenarios, @Bean methods are to be declared within @Configuration classes, ensuring that full configuration class processing applies and that cross-method references therefore get redirected to the container’s lifecycle management. This prevents the same @Bean method from accidentally being invoked through a regular Java method call, which helps to reduce subtle bugs that can be hard to track down.

When @Bean methods are declared within classes that are not annotated with @Configuration - or when @Configuration(proxyBeanMethods=false) is declared -, they are referred to as being processed in a "lite" mode. In such scenarios, @Bean methods are effectively a general-purpose factory method mechanism without special runtime processing (that is, without generating a CGLIB subclass for it). A custom Java call to such a method will not get intercepted by the container and therefore behaves just like a regular method call, creating a new instance every time rather than reusing an existing singleton (or scoped) instance for the given bean.

As a consequence, @Bean methods on classes without runtime proxying are not meant to declare inter-bean dependencies at all. Instead, they are expected to operate on their containing component’s fields and, optionally, on arguments that a factory method may declare in order to receive autowired collaborators. Such a @Bean method therefore never needs to invoke other @Bean methods; every such call can be expressed through a factory method argument instead. The positive side-effect here is that no CGLIB subclassing has to be applied at runtime, reducing the overhead and the footprint.

The @Bean and @Configuration annotations are discussed in depth in the following sections. First, however, we cover the various ways of creating a Spring container by using Java-based configuration.