Document @Bean 'lite' mode vs @Configuration
Rework the reference documentation to better distinguish the differences between @Bean methods used in @Comonent vs @Configuration classes. The 'Using the @Bean annotation' section now only covers concepts applicable when using @Bean methods in @Configuration _or_ @Component classes. Information only applicable to @Configuration classes has been moved to a new 'Using the @Configuration annotation' section. An additional sidebar section attempts to explain the differences between the two approaches. Issue: SPR-9425
This commit is contained in:
@@ -10,21 +10,46 @@
|
||||
<title>Java-based container configuration</title>
|
||||
|
||||
<section xml:id="beans-java-basic-concepts">
|
||||
<title>Basic concepts: <literal>@Configuration</literal> and
|
||||
<literal>@Bean</literal></title>
|
||||
<title>Basic concepts: <literal>@Bean</literal> and <literal>@Configuration</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>
|
||||
<sidebar>
|
||||
<title>Full @Configuration vs 'lite' @Beans mode?</title>
|
||||
<para>When <interfacename>@Bean</interfacename> methods are declared within
|
||||
classes that are <emphasis>not</emphasis> annotated with
|
||||
<interfacename>@Configuration</interfacename> they are referred to as being
|
||||
processed in a 'lite' mode. For example, bean methods declared in a
|
||||
<interfacename>@Component</interfacename> or even in a <emphasis>plain old
|
||||
class</emphasis> will be considered 'lite'.</para>
|
||||
<para>Unlike full <interfacename>@Configuration</interfacename>, lite
|
||||
<interfacename>@Bean</interfacename> methods cannot easily declare inter-bean
|
||||
dependencies. Usually one <interfacename>@Bean</interfacename> method should not
|
||||
invoke another <interfacename>@Bean</interfacename> method when operating in
|
||||
'lite' mode.</para>
|
||||
<para>Only using <interfacename>@Bean</interfacename> methods within
|
||||
<interfacename>@Configuration</interfacename> classes is a recommended approach
|
||||
of ensuring that 'full' mode is always used. This will prevent the same
|
||||
<interfacename>@Bean</interfacename> method from accidentally being invoked
|
||||
multiple times and helps to reduce subtle bugs that can be hard to track down
|
||||
when operating in 'lite' mode.</para>
|
||||
</sidebar>
|
||||
|
||||
<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:
|
||||
<para>The central artifacts in Spring's new Java-configuration support are
|
||||
<interfacename>@Configuration</interfacename>-annotated classes and
|
||||
<interfacename>@Bean</interfacename>-annotated methods.</para>
|
||||
<para>The <interfacename>@Bean</interfacename> 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
|
||||
<literal><beans/></literal> XML configuration the <literal>@Bean</literal>
|
||||
annotation plays the same role as the <literal><bean/></literal>
|
||||
element. You can use <interfacename>@Bean</interfacename> annotated methods with
|
||||
any Spring <interfacename>@Component</interfacename>, however, they are most
|
||||
often used with <interfacename>@Configuration</interfacename> beans.</para>
|
||||
<para>Annotating a class with <interfacename>@Configuration</interfacename>
|
||||
indicates that its primary purpose is as a source of bean definitions. Furthermore,
|
||||
<interfacename>@Configuration</interfacename> classes allow inter-bean
|
||||
dependencies to be defined by simply calling other <interfacename>@Bean</interfacename>
|
||||
methods in the same class. The simplest possible
|
||||
<interfacename>@Configuration</interfacename> class would read as follows:
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
@Bean
|
||||
@@ -33,16 +58,15 @@ public class AppConfig {
|
||||
}
|
||||
}</programlisting></para>
|
||||
|
||||
<para>For those more familiar with Spring <literal><beans/></literal>
|
||||
XML, the <literal>AppConfig</literal> class above would be equivalent to:
|
||||
<para>The <literal>AppConfig</literal> class above would be equivalent to the
|
||||
following Spring <literal><beans/></literal> XML:
|
||||
<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>
|
||||
The <interfacename>@Bean</interfacename> and <interfacename>@Configuration</interfacename>
|
||||
annotations 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 xml:id="beans-java-instantiating-container">
|
||||
@@ -218,6 +242,387 @@ public class AppConfig {
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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 xml:id="beans-java-lifecycle-callbacks">
|
||||
<title>Receiving lifecycle callbacks</title>
|
||||
|
||||
<para>Any classes defined with the
|
||||
<literal>@Bean</literal> annotation support
|
||||
the regular lifecycle callbacks and 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 xml:id="beans-java-specifying-bean-scope">
|
||||
<title>Specifying bean scope</title>
|
||||
|
||||
<section xml: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 xml: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>
|
||||
|
||||
<section xml: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 xml: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 xml:id="beans-java-configuration-annotation">
|
||||
<title>Using the <interfacename>@Configuration</interfacename> annotation</title>
|
||||
<para><interfacename>@Configuration</interfacename> is a class-level annotation
|
||||
indicating that an object is a source of bean definitions.
|
||||
<interfacename>@Configuration</interfacename> classes declare beans via
|
||||
public <interfacename>@Bean</interfacename> annotated methods. Calls to
|
||||
<interfacename>@Bean</interfacename> methods on
|
||||
<interfacename>@Configuration</interfacename> classes can also be used to
|
||||
define inter-bean dependencies. See <xref linkend="beans-java-basic-concepts"/> for
|
||||
a general introduction.</para>
|
||||
|
||||
<section xml:id="beans-java-injecting-dependencies">
|
||||
<title>Injecting inter-bean 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>
|
||||
|
||||
<note>
|
||||
<para>This method of declaring inter-bean dependencies only works when
|
||||
the <interfacename>@Bean</interfacename> method is declared within a
|
||||
<interfacename>@Configuration</interfacename> class. You cannot declare
|
||||
inter-bean dependencies using plain <interfacename>@Component</interfacename>
|
||||
classes.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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. Note that as of Spring
|
||||
3.2, it is no longer necessary to add CGLIB to your classpath because
|
||||
CGLIB classes have been repackaged under org.springframework and included
|
||||
directly within the spring-core JAR.</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> 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>
|
||||
|
||||
|
||||
|
||||
|
||||
<section xml:id="beans-java-composing-configuration-classes">
|
||||
<title>Composing Java-based configurations</title>
|
||||
|
||||
@@ -547,366 +952,4 @@ jdbc.password=</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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 xml: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 xml: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 xml:id="beans-java-specifying-bean-scope">
|
||||
<title>Specifying bean scope</title>
|
||||
|
||||
<section xml: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 xml: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 xml: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 xml: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 xml: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 xml: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. Note that as of Spring
|
||||
3.2, it is no longer necessary to add CGLIB to your classpath because
|
||||
CGLIB classes have been repackaged under org.springframework and included
|
||||
directly within the spring-core JAR.</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> 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>
|
||||
|
||||
Reference in New Issue
Block a user