909 lines
40 KiB
XML
909 lines
40 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<section id="beans-java">
|
|
<title>Java-based container configuration</title>
|
|
|
|
<section id="beans-java-basic-concepts">
|
|
<title>Basic concepts: <literal>@Configuration</literal> and
|
|
<literal>@Bean</literal></title>
|
|
|
|
<para>The central artifact in Spring's new Java-configuration support is the
|
|
<interfacename>@Configuration</interfacename>-annotated class. These
|
|
classes consist principally of
|
|
<interfacename>@Bean</interfacename>-annotated methods that define
|
|
instantiation, configuration, and initialization logic for objects to be
|
|
managed by the Spring IoC container.</para>
|
|
|
|
<para>Annotating a class with the
|
|
<interfacename>@Configuration</interfacename> indicates that the class can
|
|
be used by the Spring IoC container as a source of bean definitions. The
|
|
simplest possible <interfacename>@Configuration</interfacename> class
|
|
would read as follows:
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
@Bean
|
|
public MyService myService() {
|
|
return new MyServiceImpl();
|
|
}
|
|
}</programlisting></para>
|
|
|
|
<para>For those more familiar with Spring <literal><beans/></literal>
|
|
XML, the <literal>AppConfig</literal> class above would be equivalent to:
|
|
<programlisting language="xml"><beans>
|
|
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
|
|
</beans></programlisting>
|
|
As you can see, the <literal>@Bean</literal> annotation plays the same
|
|
role as the <literal><bean/></literal> element. The
|
|
<literal>@Bean</literal> annotation will be discussed in depth in the
|
|
sections below. First, however, we'll cover the various ways of creating a
|
|
spring container using Java-based configuration.</para>
|
|
</section>
|
|
|
|
<section id="beans-java-instantiating-container">
|
|
<title>Instantiating the Spring container using
|
|
<literal>AnnotationConfigApplicationContext</literal></title>
|
|
|
|
<para>The sections below document Spring's
|
|
<literal>AnnotationConfigApplicationContext</literal>, new in Spring 3.0.
|
|
This versatile <literal>ApplicationContext</literal> implementation is
|
|
capable of accepting not only <literal>@Configuration</literal> classes as
|
|
input, but also plain <literal>@Component</literal> classes and classes
|
|
annotated with JSR-330 metadata.</para>
|
|
|
|
<para>When <literal>@Configuration</literal> classes are provided as input,
|
|
the <literal>@Configuration</literal> class itself is registered as a bean
|
|
definition, and all declared <literal>@Bean</literal> methods within the
|
|
class are also registered as bean definitions.</para>
|
|
|
|
<para>When <literal>@Component</literal> and JSR-330 classes are provided,
|
|
they are registered as bean definitions, and it is assumed that DI
|
|
metadata such as <literal>@Autowired</literal> or
|
|
<literal>@Inject</literal> are used within those classes where
|
|
necessary.</para>
|
|
|
|
<section id="beans-java-instantiating-container-contstructor">
|
|
<title>Simple construction</title>
|
|
|
|
<para>In much the same way that Spring XML files are used as input when
|
|
instantiating a <literal>ClassPathXmlApplicationContext</literal>,
|
|
<literal>@Configuration</literal> classes may be used as input when
|
|
instantiating an <literal>AnnotationConfigApplicationContext</literal>.
|
|
This allows for completely XML-free usage of the Spring container:
|
|
<programlisting language="java">public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
|
MyService myService = ctx.getBean(MyService.class);
|
|
myService.doStuff();
|
|
}</programlisting>
|
|
As mentioned above,
|
|
<literal>AnnotationConfigApplicationContext</literal> is not limited to
|
|
working only with <literal>@Configuration</literal> classes. Any
|
|
<literal>@Component</literal> or JSR-330 annotated class may be supplied
|
|
as input to the constructor. For example:
|
|
<programlisting language="java">public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
|
|
MyService myService = ctx.getBean(MyService.class);
|
|
myService.doStuff();
|
|
}</programlisting>
|
|
The above assumes that <literal>MyServiceImpl</literal>,
|
|
<literal>Dependency1</literal> and <literal>Dependency2</literal> use
|
|
Spring dependency injection annotations such as
|
|
<literal>@Autowired</literal>.</para>
|
|
</section>
|
|
|
|
<section id="beans-java-instantiating-container-register">
|
|
<title>Building the container programmatically using
|
|
<literal>register(Class<?>...)</literal></title>
|
|
|
|
<para>An <literal>AnnotationConfigApplicationContext</literal> may be
|
|
instantiated using a no-arg constructor and then configured using the
|
|
<literal>register()</literal> method. This approach is particularly
|
|
useful when programmatically building an
|
|
<literal>AnnotationConfigApplicationContext</literal>.
|
|
<programlisting language="java">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();
|
|
}</programlisting></para>
|
|
</section>
|
|
|
|
<section id="beans-java-instantiating-container-scan">
|
|
<title>Enabling component scanning with
|
|
<literal>scan(String...)</literal></title>
|
|
|
|
<para>Experienced Spring users will be familiar with the following
|
|
commonly-used XML declaration from Spring's <literal>context:</literal>
|
|
namespace
|
|
<programlisting language="xml"><beans>
|
|
<context:component-scan base-package="com.acme"/>
|
|
</beans></programlisting>
|
|
In the example above, the <literal>com.acme</literal> package will be
|
|
scanned, looking for any <literal>@Component</literal>-annotated
|
|
classes, and those classes will be registered as Spring bean definitions
|
|
within the container.
|
|
<literal>AnnotationConfigApplicationContext</literal> exposes the
|
|
<literal>scan(String...)</literal> method to allow for the same
|
|
component-scanning
|
|
functionality:<programlisting language="java">public static void main(String[] args) {
|
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
|
ctx.scan("com.acme");
|
|
ctx.refresh();
|
|
MyService myService = ctx.getBean(MyService.class);
|
|
}</programlisting></para>
|
|
|
|
<note>
|
|
<para>Remember that <literal>@Configuration</literal> classes are
|
|
meta-annotated with <literal>@Component</literal>, so they are
|
|
candidates for component-scanning! In the example above, assuming that
|
|
<literal>AppConfig</literal> is declared within the
|
|
<literal>com.acme</literal> package (or any package underneath), it
|
|
will be picked up during the call to <literal>scan()</literal>, and
|
|
upon <literal>refresh()</literal> all its <literal>@Bean</literal>
|
|
methods will be processed and registered as bean definitions within
|
|
the container.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="beans-java-instantiating-container-web">
|
|
<title>Support for web applications with
|
|
<literal>AnnotationConfigWebApplicationContext</literal></title>
|
|
|
|
<para>A <literal>WebApplicationContext</literal> variant of
|
|
<literal>AnnotationConfigApplicationContext</literal> is available with
|
|
<literal>AnnotationConfigWebApplicationContext</literal>. This
|
|
implementation may be used when configuring the Spring
|
|
<literal>ContextLoaderListener</literal> servlet listener, Spring MVC
|
|
<literal>DispatcherServlet</literal>, etc. What follows is a
|
|
<literal>web.xml</literal> snippet that configures a typical Spring MVC
|
|
web application. Note the use of the <literal>contextClass</literal>
|
|
context-param and init-param:
|
|
<programlisting language="xml">
|
|
<web-app>
|
|
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
|
|
instead of the default XmlWebApplicationContext -->
|
|
<context-param>
|
|
<param-name>contextClass</param-name>
|
|
<param-value>
|
|
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
|
</param-value>
|
|
</context-param>
|
|
|
|
<!-- Configuration locations must consist of one or more comma- or space-delimited
|
|
fully-qualified @Configuration classes. Fully-qualified packages may also be
|
|
specified for component-scanning -->
|
|
<context-param>
|
|
<param-name>contextConfigLocation</param-name>
|
|
<param-value>com.acme.AppConfig</param-value>
|
|
</context-param>
|
|
|
|
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
|
|
<listener>
|
|
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
|
</listener>
|
|
|
|
<!-- Declare a Spring MVC DispatcherServlet as usual -->
|
|
<servlet>
|
|
<servlet-name>dispatcher</servlet-name>
|
|
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
|
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
|
|
instead of the default XmlWebApplicationContext -->
|
|
<init-param>
|
|
<param-name>contextClass</param-name>
|
|
<param-value>
|
|
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
|
</param-value>
|
|
</init-param>
|
|
<!-- Again, config locations must consist of one or more comma- or space-delimited
|
|
and fully-qualified @Configuration classes -->
|
|
<init-param>
|
|
<param-name>contextConfigLocation</param-name>
|
|
<param-value>com.acme.web.MvcConfig</param-value>
|
|
</init-param>
|
|
</servlet>
|
|
|
|
<!-- map all requests for /main/* to the dispatcher servlet -->
|
|
<servlet-mapping>
|
|
<servlet-name>dispatcher</servlet-name>
|
|
<url-pattern>/main/*</url-pattern>
|
|
</servlet-mapping>
|
|
</web-app></programlisting></para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-composing-configuration-classes">
|
|
<title>Composing Java-based configurations</title>
|
|
|
|
<section id="beans-java-using-import">
|
|
<title>Using the <literal>@Import</literal> annotation</title>
|
|
|
|
<para>Much as the <literal><import/></literal> element is used
|
|
within Spring XML files to aid in modularizing configurations, the
|
|
<literal>@Import</literal> annotation allows for loading
|
|
<literal>@Bean</literal> definitions from another configuration
|
|
class:<programlisting language="java">@Configuration
|
|
public class ConfigA {
|
|
public @Bean A a() { return new A(); }
|
|
}
|
|
|
|
@Configuration
|
|
@Import(ConfigA.class)
|
|
public class ConfigB {
|
|
public @Bean B b() { return new B(); }
|
|
}</programlisting>
|
|
Now, rather than needing to specify both
|
|
<literal>ConfigA.class</literal> and <literal>ConfigB.class</literal>
|
|
when instantiating the context, only <literal>ConfigB</literal> needs to
|
|
be supplied
|
|
explicitly:<programlisting language="java">public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
|
|
|
|
// now both beans A and B will be available...
|
|
A a = ctx.getBean(A.class);
|
|
B b = ctx.getBean(B.class);
|
|
}</programlisting>
|
|
This approach simplifies container instantiation, as only one class
|
|
needs to be dealt with, rather than requiring the developer to remember
|
|
a potentially large number of <literal>@Configuration</literal> classes
|
|
during construction.</para>
|
|
|
|
<section id="beans-java-injecting-imported-beans">
|
|
<title>Injecting dependencies on imported <literal>@Bean</literal>
|
|
definitions</title>
|
|
|
|
<para>The example above works, but is simplistic. In most practical
|
|
scenarios, beans will have dependencies on one another across
|
|
configuration classes. When using XML, this is not an issue, per se,
|
|
because there is no compiler involved, and one can simply declare
|
|
<literal>ref="someBean"</literal> and trust that Spring will work it
|
|
out during container initialization. Of course, when using
|
|
<literal>@Configuration</literal> classes, the Java compiler places
|
|
constraints on the configuration model, in that references to other
|
|
beans must be valid Java syntax.</para>
|
|
|
|
<para>Fortunately, solving this problem is simple. Remember that
|
|
<literal>@Configuration</literal> classes are ultimately just another
|
|
bean in the container - this means that they can take advantage of
|
|
<literal>@Autowired</literal> injection metadata just like any other
|
|
bean!</para>
|
|
|
|
<para>Let's consider a more real-world scenario with several
|
|
<literal>@Configuration</literal> classes, each depending on beans
|
|
declared in the
|
|
others:<programlisting language="java">@Configuration
|
|
public class ServiceConfig {
|
|
private @Autowired AccountRepository accountRepository;
|
|
|
|
public @Bean TransferService transferService() {
|
|
return new TransferServiceImpl(accountRepository);
|
|
}
|
|
}
|
|
|
|
@Configuration
|
|
public class RepositoryConfig {
|
|
private @Autowired DataSource dataSource;
|
|
|
|
public @Bean AccountRepository accountRepository() {
|
|
return new JdbcAccountRepository(dataSource);
|
|
}
|
|
}
|
|
|
|
@Configuration
|
|
@Import({ServiceConfig.class, RepositoryConfig.class})
|
|
public class SystemTestConfig {
|
|
public @Bean DataSource dataSource() { /* return new DataSource */ }
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
|
|
// everything wires up across configuration classes...
|
|
TransferService transferService = ctx.getBean(TransferService.class);
|
|
transferService.transfer(100.00, "A123", "C456");
|
|
}</programlisting></para>
|
|
|
|
<section id="beans-java-injecting-imported-beans-fq">
|
|
<title>Fully-qualifying imported beans for ease of navigation</title>
|
|
|
|
<para>In the scenario above, using <literal>@Autowired</literal> works
|
|
well and provides the desired modularity, but determining exactly
|
|
where the autowired bean definitions are declared is still somewhat
|
|
ambiguous. For example, as a developer looking at
|
|
<literal>ServiceConfig</literal>, how do you know exactly where the
|
|
<literal>@Autowired AccountRepository</literal> bean is declared?
|
|
It's not explicit in the code, and this may be just fine. Remember
|
|
that the <ulink url="http://www.springsource.com/products/sts"
|
|
>SpringSource Tool Suite</ulink> provides tooling that can render
|
|
graphs showing how everything is wired up - that may be all you
|
|
need. Also, your Java IDE can easily find all declarations and uses
|
|
of the <literal>AccountRepository</literal> type, and will quickly
|
|
show you the location of <literal>@Bean</literal> methods that
|
|
return that type.</para>
|
|
|
|
<para>In cases where this ambiguity is not acceptable and you wish to
|
|
have direct navigation from within your IDE from one
|
|
<literal>@Configuration</literal> class to another, consider
|
|
autowiring the configuration classes themselves:
|
|
<programlisting language="java">@Configuration
|
|
public class ServiceConfig {
|
|
private @Autowired RepositoryConfig repositoryConfig;
|
|
|
|
public @Bean TransferService transferService() {
|
|
// navigate 'through' the config class to the @Bean method!
|
|
return new TransferServiceImpl(repositoryConfig.accountRepository());
|
|
}
|
|
}</programlisting>
|
|
In the situation above, it is completely explicit where
|
|
<literal>AccountRepository</literal> is defined. However,
|
|
<literal>ServiceConfig</literal> is now tightly coupled to
|
|
<literal>RepositoryConfig</literal>; that's the tradeoff. This tight
|
|
coupling can be somewhat mitigated by using interface-based or
|
|
abstract class-based <literal>@Configuration</literal> classes.
|
|
Consider the following:
|
|
<programlisting language="java">@Configuration
|
|
public class ServiceConfig {
|
|
private @Autowired RepositoryConfig repositoryConfig;
|
|
|
|
public @Bean TransferService transferService() {
|
|
return new TransferServiceImpl(repositoryConfig.accountRepository());
|
|
}
|
|
}
|
|
|
|
@Configuration
|
|
public interface RepositoryConfig {
|
|
@Bean AccountRepository accountRepository();
|
|
}
|
|
|
|
@Configuration
|
|
public class DefaultRepositoryConfig implements RepositoryConfig {
|
|
public @Bean AccountRepository accountRepository() {
|
|
return new JdbcAccountRepository(...);
|
|
}
|
|
}
|
|
|
|
@Configuration
|
|
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
|
|
public class SystemTestConfig {
|
|
public @Bean DataSource dataSource() { /* return DataSource */ }
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
|
|
TransferService transferService = ctx.getBean(TransferService.class);
|
|
transferService.transfer(100.00, "A123", "C456");
|
|
}</programlisting>
|
|
Now <literal>ServiceConfig</literal> is loosely coupled with respect
|
|
to the concrete <literal>DefaultRepositoryConfig</literal>, and
|
|
built-in IDE tooling is still useful: it will be easy for the
|
|
developer to get a type hierarchy of
|
|
<literal>RepositoryConfig</literal> implementations. In this way,
|
|
navigating <literal>@Configuration</literal> classes and their
|
|
dependencies becomes no different than the usual process of
|
|
navigating interface-based code.</para>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-combining">
|
|
<title>Combining Java and XML configuration</title>
|
|
|
|
<para>Spring's <literal>@Configuration</literal> class support does not
|
|
aim to be a 100% complete replacement for Spring XML. Some facilities
|
|
such as Spring XML namespaces remain an ideal way to configure the
|
|
container. In cases where XML is convenient or necessary, you have a
|
|
choice: either instantiate the container in an "XML-centric" way using,
|
|
for example, <literal>ClassPathXmlApplicationContext</literal>, or in a
|
|
"Java-centric" fashion using
|
|
<literal>AnnotationConfigApplicationContext</literal> and the
|
|
<literal>@ImportResource</literal> annotation to import XML as
|
|
needed.</para>
|
|
|
|
<section id="beans-java-combining-xml-centric">
|
|
<title>XML-centric use of <literal>@Configuration</literal>
|
|
classes</title>
|
|
|
|
<para>It may be preferable to bootstrap the Spring container from XML
|
|
and include <literal>@Configuration</literal> classes in an ad-hoc
|
|
fashion. For example, in a large existing codebase that uses Spring
|
|
XML, it will be easier to create <literal>@Configuration</literal>
|
|
classes on an as-needed basis and include them from the existing XML
|
|
files. Below you'll find the options for using
|
|
<literal>@Configuration</literal> classes in this kind of
|
|
"XML-centric" situation.</para>
|
|
|
|
<section id="beans-java-combining-xml-centric-declare-as-bean">
|
|
<title>Declaring <literal>@Configuration</literal> classes as plain
|
|
Spring <literal><bean/></literal> elements</title>
|
|
|
|
<para>Remember that <literal>@Configuration</literal> classes are
|
|
ultimately just bean definitions in the container. In this example,
|
|
we create a <literal>@Configuration</literal> class named
|
|
<literal>AppConfig</literal> and include it within
|
|
<literal>system-test-config.xml</literal> as a
|
|
<literal><bean/></literal>definition. Because
|
|
<literal><context:annotation-config/></literal> is switched
|
|
on, the container will recognize the
|
|
<literal>@Configuration</literal> annotation, and process the
|
|
<literal>@Bean</literal> methods declared in
|
|
<literal>AppConfig</literal>
|
|
properly.<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
private @Autowired DataSource dataSource;
|
|
|
|
public @Bean AccountRepository accountRepository() {
|
|
return new JdbcAccountRepository(dataSource);
|
|
}
|
|
|
|
public @Bean TransferService transferService() {
|
|
return new TransferService(accountRepository());
|
|
}
|
|
}</programlisting>
|
|
<programlisting language="xml"><lineannotation role="listingtitle">system-test-config.xml</lineannotation>
|
|
<beans>
|
|
<!-- enable processing of annotations such as @Autowired and @Configuration -->
|
|
<context:annotation-config/>
|
|
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
|
|
|
<bean class="com.acme.AppConfig"/>
|
|
|
|
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
|
<property name="url" value="${jdbc.url}"/>
|
|
<property name="username" value="${jdbc.username}"/>
|
|
<property name="password" value="${jdbc.password}"/>
|
|
</bean>
|
|
</beans></programlisting>
|
|
<programlisting><lineannotation role="listingtitle">jdbc.properties</lineannotation>
|
|
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
|
|
jdbc.username=sa
|
|
jdbc.password=</programlisting>
|
|
<programlisting language="java">public static void main(String[] args) {
|
|
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
|
|
TransferService transferService = ctx.getBean(TransferService.class);
|
|
// ...
|
|
}</programlisting></para>
|
|
|
|
<note>
|
|
<para>In <literal>system-test-config.xml</literal> above, the
|
|
<literal>AppConfig<bean/></literal> does not declare an
|
|
<literal>id</literal> element. While it would be acceptable to do
|
|
so, it is unnecessary given that no other bean will ever refer to
|
|
it, and it is unlikely that it will be explicitly fetched from the
|
|
container by name. Likewise with the <literal>DataSource</literal>
|
|
bean - it is only ever autowired by type, so an explicit bean id
|
|
is not strictly required.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="beans-java-combining-xml-centric-component-scan">
|
|
<title>Using <literal><context:component-scan/></literal> to
|
|
pick up <literal>@Configuration</literal> classes</title>
|
|
|
|
<para>Because <literal>@Configuration</literal> is meta-annotated with
|
|
<literal>@Component</literal>,
|
|
<literal>@Configuration</literal>-annotated classes are
|
|
automatically candidates for component scanning. Using the same
|
|
scenario as above, we can redefine
|
|
<literal>system-test-config.xml</literal> to take advantage of
|
|
component-scanning. Note that in this case, we don't need to
|
|
explicitly declare
|
|
<literal><context:annotation-config/></literal>, because
|
|
<literal><context:component-scan/></literal> enables all the
|
|
same
|
|
functionality.<programlisting language="xml"><lineannotation role="listingtitle">system-test-config.xml</lineannotation>
|
|
<beans>
|
|
<!-- picks up and registers AppConfig as a bean definition -->
|
|
<context:component-scan base-package="com.acme"/>
|
|
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
|
|
|
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
|
<property name="url" value="${jdbc.url}"/>
|
|
<property name="username" value="${jdbc.username}"/>
|
|
<property name="password" value="${jdbc.password}"/>
|
|
</bean>
|
|
</beans></programlisting></para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-combining-java-centric">
|
|
<title><literal>@Configuration</literal> class-centric use of XML with
|
|
<literal>@ImportResource</literal></title>
|
|
|
|
<para>In applications where <literal>@Configuration</literal> classes
|
|
are the primary mechanism for configuring the container, it will still
|
|
likely be necessary to use at least some XML. In these scenarios,
|
|
simply use <literal>@ImportResource</literal> and define only as much
|
|
XML as is needed. Doing so achieves a "Java-centric" approach to
|
|
configuring the container and keeps XML to a bare minimum.
|
|
<programlisting language="java">@Configuration
|
|
@ImportResource("classpath:/com/acme/properties-config.xml")
|
|
public class AppConfig {
|
|
private @Value("${jdbc.url}") String url;
|
|
private @Value("${jdbc.username}") String username;
|
|
private @Value("${jdbc.password}") String password;
|
|
|
|
public @Bean DataSource dataSource() {
|
|
return new DriverManagerDataSource(url, username, password);
|
|
}
|
|
}</programlisting>
|
|
<programlisting language="xml"><lineannotation role="listingtitle">properties-config.xml</lineannotation>
|
|
<beans>
|
|
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
|
</beans></programlisting>
|
|
<programlisting><lineannotation role="listingtitle">jdbc.properties</lineannotation>
|
|
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
|
|
jdbc.username=sa
|
|
jdbc.password=</programlisting>
|
|
<programlisting language="java">public static void main(String[] args) {
|
|
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
|
TransferService transferService = ctx.getBean(TransferService.class);
|
|
// ...
|
|
}</programlisting></para>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-bean-annotation">
|
|
<title>Using the <interfacename>@Bean</interfacename> annotation</title>
|
|
|
|
<para><interfacename>@Bean</interfacename> is a method-level annotation and
|
|
a direct analog of the XML <code><bean/></code> element. The
|
|
annotation supports some of the attributes offered by
|
|
<code><bean/></code>, such as: <code><link
|
|
linkend="beans-factory-lifecycle-initializingbean"
|
|
>init-method</link></code>, <code><link
|
|
linkend="beans-factory-lifecycle-disposablebean"
|
|
>destroy-method</link></code>, <code><link
|
|
linkend="beans-factory-autowire">autowiring</link></code> and
|
|
<code>name</code>.</para>
|
|
|
|
<para>You can use the <interfacename>@Bean</interfacename> annotation in a
|
|
<interfacename>@Configuration</interfacename>-annotated or in a
|
|
<interfacename>@Component</interfacename>-annotated class.</para>
|
|
|
|
<section id="beans-java-declaring-a-bean">
|
|
<title>Declaring a bean</title>
|
|
|
|
<para>To declare a bean, simply annotate a method with the
|
|
<interfacename>@Bean</interfacename> annotation. You use this method to
|
|
register a bean definition within an <code>ApplicationContext</code> of
|
|
the type specified as the method's return value. By default, the bean
|
|
name will be the same as the method name. The following is a simple
|
|
example of a <interfacename>@Bean</interfacename> method declaration:
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
|
|
@Bean
|
|
public TransferService transferService() {
|
|
return new TransferServiceImpl();
|
|
}
|
|
|
|
}</programlisting></para>
|
|
|
|
<para>The preceding configuration is exactly equivalent to the following
|
|
Spring XML:
|
|
<programlisting language="xml"><beans>
|
|
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
|
|
</beans> </programlisting></para>
|
|
|
|
<para>Both declarations make a bean named <code>transferService</code>
|
|
available in the <code>ApplicationContext</code>, bound to an object
|
|
instance of type <code>TransferServiceImpl</code>:
|
|
<programlisting>
|
|
transferService -> com.acme.TransferServiceImpl
|
|
</programlisting></para>
|
|
</section>
|
|
|
|
<section id="beans-java-injecting-dependencies">
|
|
<title>Injecting dependencies</title>
|
|
|
|
<para>When <interfacename>@Bean</interfacename>s have dependencies on one
|
|
another, expressing that dependency is as simple as having one bean
|
|
method call another:
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
|
|
@Bean
|
|
public Foo foo() {
|
|
return new Foo(bar());
|
|
}
|
|
|
|
@Bean
|
|
public Bar bar() {
|
|
return new Bar();
|
|
}
|
|
|
|
} </programlisting></para>
|
|
|
|
<para>In the example above, the <code>foo</code> bean receives a reference
|
|
to <code> bar</code> via constructor injection.</para>
|
|
</section>
|
|
|
|
<section id="beans-java-lifecycle-callbacks">
|
|
<title>Receiving lifecycle callbacks</title>
|
|
|
|
<para>Beans declared in a
|
|
<interfacename>@Configuration</interfacename>-annotated class support
|
|
the regular lifecycle callbacks. Any classes defined with the
|
|
<literal>@Bean</literal> annotation can use the
|
|
<literal>@PostConstruct</literal> and <literal>@PreDestroy</literal>
|
|
annotations from JSR-250, see <link
|
|
linkend="beans-postconstruct-and-predestroy-annotations">JSR-250
|
|
annotations</link> for further details.</para>
|
|
|
|
<para>The regular Spring <link linkend="beans-factory-nature"
|
|
>lifecycle</link> callbacks are fully supported as well. If a bean
|
|
implements <code>InitializingBean</code>, <code>DisposableBean</code>,
|
|
or <code>Lifecycle</code>, their respective methods are called by the
|
|
container.</para>
|
|
|
|
<para>The standard set of <code>*Aware</code> interfaces such as
|
|
<code><link linkend="beans-beanfactory">BeanFactoryAware</link></code>,
|
|
<code><link linkend="beans-factory-aware">BeanNameAware</link></code>,
|
|
<code><link linkend="context-functionality-messagesource"
|
|
>MessageSourceAware</link></code>, <code><link
|
|
linkend="beans-factory-aware">ApplicationContextAware</link></code>, and
|
|
so on are also fully supported.</para>
|
|
|
|
<para>The <interfacename>@Bean</interfacename> annotation supports
|
|
specifying arbitrary initialization and destruction callback methods,
|
|
much like Spring XML's <code>init-method</code> and
|
|
<code>destroy-method</code> attributes on the <code>bean</code> element:
|
|
<programlisting language="java">public class Foo {
|
|
public void init() {
|
|
// initialization logic
|
|
}
|
|
}
|
|
|
|
public class Bar {
|
|
public void cleanup() {
|
|
// destruction logic
|
|
}
|
|
}
|
|
|
|
@Configuration
|
|
public class AppConfig {
|
|
@Bean(initMethod = "init")
|
|
public Foo foo() {
|
|
return new Foo();
|
|
}
|
|
@Bean(destroyMethod = "cleanup")
|
|
public Bar bar() {
|
|
return new Bar();
|
|
}
|
|
}
|
|
</programlisting></para>
|
|
|
|
<para>Of course, in the case of <code>Foo</code> above, it would be
|
|
equally as valid to call the <code>init()</code> method directly during
|
|
construction:
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
@Bean
|
|
public Foo foo() {
|
|
Foo foo = new Foo();
|
|
foo.init();
|
|
return foo;
|
|
}
|
|
|
|
// ...
|
|
} </programlisting></para>
|
|
|
|
<tip>
|
|
<para>When you work directly in Java, you can do anything you like with
|
|
your objects and do not always need to rely on the container
|
|
lifecycle!</para>
|
|
</tip>
|
|
</section>
|
|
|
|
<section id="beans-java-specifying-bean-scope">
|
|
<title>Specifying bean scope</title>
|
|
|
|
<section id="beans-java-available-scopes">
|
|
<title>Using the <interfacename>@Scope</interfacename>
|
|
annotation</title>
|
|
|
|
<!-- MLP: Beverly, did not apply your edit as it changed meaning -->
|
|
|
|
<para>You can specify that your beans defined with the
|
|
<interfacename>@Bean</interfacename> annotation should have a specific
|
|
scope. You can use any of the standard scopes specified in the <link
|
|
linkend="beans-factory-scopes">Bean Scopes</link> section.</para>
|
|
|
|
<para>The default scope is <literal>singleton</literal>, but you can
|
|
override this with the <interfacename>@Scope</interfacename>
|
|
annotation:
|
|
<programlisting language="java">@Configuration
|
|
public class MyConfiguration {
|
|
@Bean
|
|
<emphasis role="bold">@Scope("prototype")</emphasis>
|
|
public Encryptor encryptor() {
|
|
// ...
|
|
}
|
|
}</programlisting></para>
|
|
</section>
|
|
|
|
<section id="beans-java-scoped-proxy">
|
|
<title><code>@Scope and scoped-proxy</code></title>
|
|
|
|
<para>Spring offers a convenient way of working with scoped dependencies
|
|
through <link linkend="beans-factory-scopes-other-injection">scoped
|
|
proxies</link>. The easiest way to create such a proxy when using the
|
|
XML configuration is the <code><aop:scoped-proxy/></code>
|
|
element. Configuring your beans in Java with a @Scope annotation
|
|
offers equivalent support with the proxyMode attribute. The default is
|
|
no proxy (<varname>ScopedProxyMode.NO</varname>), but you can specify
|
|
<classname>ScopedProxyMode.TARGET_CLASS</classname> or
|
|
<classname>ScopedProxyMode.INTERFACES</classname>.</para>
|
|
|
|
<para>If you port the scoped proxy example from the XML reference
|
|
documentation (see preceding link) to our
|
|
<interfacename>@Bean</interfacename> using Java, it would look like
|
|
the following:
|
|
<programlisting language="java">// an HTTP Session-scoped bean exposed as a proxy
|
|
@Bean
|
|
<emphasis role="bold">@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)</emphasis>
|
|
public UserPreferences userPreferences() {
|
|
return new UserPreferences();
|
|
}
|
|
|
|
@Bean
|
|
public Service userService() {
|
|
UserService service = new SimpleUserService();
|
|
// a reference to the proxied userPreferences bean
|
|
service.setUserPreferences(userPreferences());
|
|
return service;
|
|
} </programlisting></para>
|
|
</section>
|
|
|
|
<section id="beans-java-method-injection">
|
|
<title>Lookup method injection</title>
|
|
|
|
<para>As noted earlier, <link linkend="beans-factory-method-injection"
|
|
>lookup method injection</link> is an advanced feature that you should
|
|
use rarely. It is useful in cases where a singleton-scoped bean has a
|
|
dependency on a prototype-scoped bean. Using Java for this type of
|
|
configuration provides a natural means for implementing this pattern.
|
|
<programlisting language="java">public abstract class CommandManager {
|
|
public Object process(Object commandState) {
|
|
// grab a new instance of the appropriate Command interface
|
|
Command command = createCommand();
|
|
|
|
// set the state on the (hopefully brand new) Command instance
|
|
command.setState(commandState);
|
|
return command.execute();
|
|
}
|
|
|
|
// okay... but where is the implementation of this method?
|
|
protected abstract Command createCommand();
|
|
} </programlisting></para>
|
|
|
|
<para>Using Java-configuration support , you can create a subclass of
|
|
<code>CommandManager</code> where the abstract
|
|
<code>createCommand()</code> method is overridden in such a way that
|
|
it looks up a new (prototype) command object:
|
|
<programlisting language="java">@Bean
|
|
@Scope("prototype")
|
|
public AsyncCommand asyncCommand() {
|
|
AsyncCommand command = new AsyncCommand();
|
|
// inject dependencies here as required
|
|
return command;
|
|
}
|
|
|
|
@Bean
|
|
public CommandManager commandManager() {
|
|
// return new anonymous implementation of CommandManager with command() overridden
|
|
// to return a new prototype Command object
|
|
return new CommandManager() {
|
|
protected Command createCommand() {
|
|
return asyncCommand();
|
|
}
|
|
}
|
|
} </programlisting></para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-customizing-bean-naming">
|
|
<title>Customizing bean naming</title>
|
|
|
|
<para>By default, configuration classes use a
|
|
<interfacename>@Bean</interfacename> method's name as the name of the
|
|
resulting bean. This functionality can be overridden, however, with the
|
|
<code>name</code> attribute.
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
|
|
@Bean(name = "myFoo")
|
|
public Foo foo() {
|
|
return new Foo();
|
|
}
|
|
|
|
} </programlisting></para>
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section id="beans-java-bean-aliasing">
|
|
<title>Bean aliasing</title>
|
|
|
|
<para>As discussed in <xref linkend="beans-beanname"/>, it is sometimes
|
|
desirable to give a single bean multiple names, otherwise known as
|
|
<emphasis>bean aliasing</emphasis>. The <literal>name</literal>
|
|
attribute of the <literal>@Bean</literal> annotation accepts a String
|
|
array for this purpose.
|
|
<programlisting language="java">@Configuration
|
|
public class AppConfig {
|
|
|
|
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
|
|
public DataSource dataSource() {
|
|
// instantiate, configure and return DataSource bean...
|
|
}
|
|
|
|
} </programlisting></para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="beans-java-further-information-java-config">
|
|
<title>Further information about how Java-based configuration works
|
|
internally</title>
|
|
|
|
<para>The following example shows a <literal>@Bean</literal> annotated
|
|
method being called twice:</para>
|
|
|
|
<programlisting language="java">
|
|
@Configuration
|
|
public class AppConfig {
|
|
|
|
@Bean
|
|
public ClientService clientService1() {
|
|
ClientServiceImpl clientService = new ClientServiceImpl();
|
|
clientService.setClientDao(clientDao());
|
|
return clientService;
|
|
}
|
|
@Bean
|
|
public ClientService clientService2() {
|
|
ClientServiceImpl clientService = new ClientServiceImpl();
|
|
clientService.setClientDao(clientDao());
|
|
return clientService;
|
|
}
|
|
|
|
@Bean
|
|
public ClientDao clientDao() {
|
|
return new ClientDaoImpl();
|
|
}
|
|
}
|
|
</programlisting>
|
|
<para> <methodname>clientDao()</methodname> has been called once in
|
|
<methodname>clientService1()</methodname> and once in
|
|
<methodname>clientService2()</methodname>. Since this method creates a new
|
|
instance of <classname>ClientDaoImpl</classname> and returns it, you would
|
|
normally expect having 2 instances (one for each service). That definitely
|
|
would be problematic: in Spring, instantiated beans have a
|
|
<literal>singleton</literal> scope by default. This is where the magic
|
|
comes in: All <literal>@Configuration</literal> classes are subclassed at
|
|
startup-time with <literal>CGLIB</literal>. In the subclass, the child
|
|
method checks the container first for any cached (scoped) beans before it
|
|
calls the parent method and creates a new instance. </para>
|
|
<note>
|
|
<para> The behavior could be different according to the scope of your
|
|
bean. We are talking about singletons here. </para>
|
|
</note>
|
|
<note>
|
|
<para> Beware that, in order for JavaConfig to work, you must include the
|
|
CGLIB jar in your list of dependencies. </para>
|
|
</note>
|
|
<note>
|
|
<para> There are a few restrictions due to the fact that CGLIB dynamically
|
|
adds features at startup-time: <itemizedlist>
|
|
<listitem>
|
|
<para>Configuration classes should not be final</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>They should have a constructor with no arguments</para>
|
|
</listitem>
|
|
</itemizedlist> </para>
|
|
</note>
|
|
</section>
|
|
</section>
|