Key concepts: @Bean
and @Configuration
The central artifacts in Spring's new Java configuration support are classes, marked with the @Configuration
annotation, and methods marked with the @Bean
annotation.
The @Bean
annotation is used to indicate that The method instantiates, configures, and initializes a new object that will be managed by the Spring IoC container. For those familiar with the <beans/>
XML configuration from Spring, the @Bean
annotation plays the same role as the <bean>
. You can use @Bean
annotated methods with any @Component
annotation from Spring. However, they are most often used with beans annotated with @Configuration
.
Annotating a class with @Configuration
indicates that its primary purpose is to be a source bean definitions. Moreover, classes annotated with @Configuration
allow you to define inter-bean dependencies by calling other @Bean
methods in the same class. The simplest possible class, annotated with @Configuration
, looks like this:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun myService(): MyService {
return MyServiceImpl()
}
}
The preceding class AppConfig
is equivalent to the following XML class <beans/> from Spring:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
The @Bean
and @Configuration
annotations are discussed in detail in the following sections. However, first we will look at the different ways to create a Spring container using Java-based configuration.
Instantiating a Spring container using AnnotationConfigApplicationContext
The following sections describe AnnotationConfigApplicationContext
introduced in Spring 3.0. This generic implementation of the ApplicationContext
interface can accept as input not only classes annotated with the @Configuration
annotation, but also regular classes annotated with the @Component
annotation, as well as classes annotated with metadata from JSR-330.
If classes annotated with the @Configuration
annotation are specified as input, the class itself annotated with @Configuration
, is registered as a bean definition, and all methods declared in the class that are marked with the @Bean
annotation are also registered as bean definitions.
If classes are specified that are marked with the @Component
, or from JSR-330, they are registered as bean definitions, and dependency injection metadata such as @Autowired
or @Inject
is assumed to be used in these classes where needed.
Simple design
Just as Spring XML files are used as input when creating a ClassPathXmlApplicationContext
, you can use classes , annotated with @Configuration
, as input when creating the AnnotationConfigApplicationContext
. This allows you to use the entire Spring container without XML, as shown in the following example:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext(AppConfig::class.java)
val myService = ctx.getBean<MyService>()
myService.doStuff()
}
As mentioned earlier, AnnotationConfigApplicationContext
is not limited to working only with classes annotated with @Configuration
. Any @Component
or JSR-330 annotated class can be provided as input to the constructor, as shown in the following example:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext(MyServiceImpl::class.java, Dependency1::class.java, Dependency2::class.java)
val myService = ctx.getBean<MyService>()
myService.doStuff()
}
The previous example assumes that MyServiceImpl
, Dependency1
and Dependency2
use Spring dependency injection annotations such as the @Autowired
.
Building a container programmatically using register(Class<?>…)
You can create AnnotationConfigApplicationContext
using a no-argument constructor and then configuring it using the register()
method. This approach is especially useful when constructing AnnotationConfigApplicationContext
programmatically. The following example shows how to do this:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
import org.springframework.beans.factory.getBean
fun main() {
val ctx = AnnotationConfigApplicationContext()
ctx.register(AppConfig::class.java, OtherConfig::class.java)
ctx.register(AdditionalConfig::class.java)
ctx.refresh()
val myService = ctx.getBean<MyService>()
myService.doStuff()
}
Enable component scanning using scan(String...)
To enable scanning components, you can annotate your class with @Configuration
like this:
@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig {
// ...
}
- This annotation allows you to scan components.
@Configuration
@ComponentScan(basePackages = ["com.acme"])
class AppConfig {
// ...
}
- This annotation allows components to be scanned.
Experienced Spring users may be familiar with the Spring equivalent of the XML declaration from the context:
namespace, shown in the following example:
<beans>
<context:component-scan base-package="com.acme"/>
</beans>
In the previous example, the package com.acme
is scanned for any classes annotated with @Component
, and these classes are registered as Spring bean definitions in the container. AnnotationConfigApplicationContext
exposes the scan(String...)
method to provide the same component scanning functionality as shown in the following example:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
fun main() {
val ctx = AnnotationConfigApplicationContext()
ctx.scan("com.acme")
ctx.refresh()
val myService = ctx.getBean<MyService>()
}
@Configuration
classes are meta-annotated with
@Component
and are therefore candidates for component scanning. In the previous example, assuming
AppConfig
is declared in the
com.acme
package (or any other package underneath it), it is intercepted during the
scan()
. After
refresh()
, all its methods annotated with
@Bean
are processed and registered as bean definitions in the container.
Supporting web applications with AnnotationConfigWebApplicationContext
The WebApplicationContext
variant of the AnnotationConfigApplicationContext
class can be accessed using AnnotationConfigWebApplicationContext
. You can use this implementation when setting up a servlet listener ContextLoaderListener
from Spring, DispatcherServlet
from Spring MVC and so on. The following web.xml
snippet configures a typical web application in Spring MVC (note the use of the contextClass
context parameters and init parameters):
<web-app>
<!-- Configuring ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the standard XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- The configuration location must consist of one or more comma- or space-separated
fully qualified class names annotated with @Configuration. Full package names can also be -->
<context-param>
<param-name>contextConfigLocation>/param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- We bootstrap the root application context as usual, using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-classм
</listener>
<!-- Declare the DispatcherServlet in Spring MVC as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure the DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the standard XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, configuration locations must consist of one or more comma- or space-separated
and fully qualified class names annotated with @Configuration -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
GenericWebApplicationContext
can be used as an alternative to
AnnotationConfigWebApplicationContext
. For details, see the javadoc at
GenericWebApplicationContext
.
GO TO FULL VERSION