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