Explicit notes for @Bean on static methods, private methods, and Java 8 default methods

Also includes an explicit note on stop vs destroy callbacks for Lifecycle beans.

Issue: SPR-13118
Issue: SPR-12882
Issue: SPR-12345
Issue: SPR-11671
This commit is contained in:
Juergen Hoeller 2015-07-07 16:49:26 +02:00
parent ca3ba7deb5
commit f58e1db2e6
2 changed files with 57 additions and 19 deletions

View File

@ -50,29 +50,33 @@ public interface Lifecycle {
/** /**
* Start this component. * Start this component.
* Should not throw an exception if the component is already running. * <p>Should not throw an exception if the component is already running.
* <p>In the case of a container, this will propagate the start signal * <p>In the case of a container, this will propagate the start signal to all
* to all components that apply. * components that apply.
* @see SmartLifecycle#isAutoStartup() * @see SmartLifecycle#isAutoStartup()
*/ */
void start(); void start();
/** /**
* Stop this component, typically in a synchronous fashion, such that * Stop this component, typically in a synchronous fashion, such that the component is
* the component is fully stopped upon return of this method. Consider * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle}
* implementing {@link SmartLifecycle} and its {@code stop(Runnable)} * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary.
* variant in cases where asynchronous stop behavior is necessary. * <p>Note that this stop notification is not guaranteed to come before destruction: On
* regular shutdown, {@code Lifecycle} beans will first receive a stop notification before
* the general destruction callbacks are being propagated; however, on hot refresh during a
* context's lifetime or on aborted refresh attempts, only destroy methods will be called.
* <p>Should not throw an exception if the component isn't started yet. * <p>Should not throw an exception if the component isn't started yet.
* <p>In the case of a container, this will propagate the stop signal * <p>In the case of a container, this will propagate the stop signal to all components
* to all components that apply. * that apply.
* @see SmartLifecycle#stop(Runnable) * @see SmartLifecycle#stop(Runnable)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/ */
void stop(); void stop();
/** /**
* Check whether this component is currently running. * Check whether this component is currently running.
* <p>In the case of a container, this will return {@code true} * <p>In the case of a container, this will return {@code true} only if <i>all</i>
* only if <i>all</i> components that apply are currently running. * components that apply are currently running.
* @return whether the component is currently running * @return whether the component is currently running
*/ */
boolean isRunning(); boolean isRunning();

View File

@ -2849,7 +2849,7 @@ unnecessarily couples the code to Spring. Alternatively, use
the <<beans-postconstruct-and-predestroy-annotations, `@PostConstruct`>> annotation or the <<beans-postconstruct-and-predestroy-annotations, `@PostConstruct`>> annotation or
specify a POJO initialization method. In the case of XML-based configuration metadata, specify a POJO initialization method. In the case of XML-based configuration metadata,
you use the `init-method` attribute to specify the name of the method that has a void you use the `init-method` attribute to specify the name of the method that has a void
no-argument signature. With Java config you use the `initMethod` attribute of `@Bean`, no-argument signature. With Java config, you use the `initMethod` attribute of `@Bean`,
see <<beans-java-lifecycle-callbacks>>. For example, the following: see <<beans-java-lifecycle-callbacks>>. For example, the following:
[source,xml,indent=0] [source,xml,indent=0]
@ -2909,8 +2909,8 @@ It is recommended that you do not use the `DisposableBean` callback interface be
unnecessarily couples the code to Spring. Alternatively, use unnecessarily couples the code to Spring. Alternatively, use
the <<beans-postconstruct-and-predestroy-annotations, `@PreDestroy`>> annotation or the <<beans-postconstruct-and-predestroy-annotations, `@PreDestroy`>> annotation or
specify a generic method that is supported by bean definitions. With XML-based specify a generic method that is supported by bean definitions. With XML-based
configuration metadata, you use the `destroy-method` attribute on the `<bean/>`. With configuration metadata, you use the `destroy-method` attribute on the `<bean/>`.
Java config you use the `destroyMethod` attribute of `@Bean`, see With Java config, you use the `destroyMethod` attribute of `@Bean`, see
<<beans-java-lifecycle-callbacks>>. For example, the following definition: <<beans-java-lifecycle-callbacks>>. For example, the following definition:
[source,xml,indent=0] [source,xml,indent=0]
@ -3122,6 +3122,10 @@ Note that the regular `org.springframework.context.Lifecycle` interface is just
contract for explicit start/stop notifications and does NOT imply auto-startup at context contract for explicit start/stop notifications and does NOT imply auto-startup at context
refresh time. Consider implementing `org.springframework.context.SmartLifecycle` instead refresh time. Consider implementing `org.springframework.context.SmartLifecycle` instead
for fine-grained control over auto-startup of a specific bean (including startup phases). for fine-grained control over auto-startup of a specific bean (including startup phases).
Also, please note that stop notifications are not guaranteed to come before destruction:
On regular shutdown, all `Lifecycle` beans will first receive a stop notification before
the general destruction callbacks are being propagated; however, on hot refresh during a
context's lifetime or on aborted refresh attempts, only destroy methods will be called.
==== ====
The order of startup and shutdown invocations can be important. If a "depends-on" The order of startup and shutdown invocations can be important. If a "depends-on"
@ -5128,8 +5132,8 @@ will in effect disable automatic detection of classes annotated with `@Component
[[beans-factorybeans-annotations]] [[beans-factorybeans-annotations]]
=== Defining bean metadata within components === Defining bean metadata within components
Spring components can also contribute bean definition metadata to the container. You do Spring components can also contribute bean definition metadata to the container. You do
this with the same `@Bean` annotation used to define bean metadata within this with the same `@Bean` annotation used to define bean metadata within `@Configuration`
`@Configuration` annotated classes. Here is a simple example: annotated classes. Here is a simple example:
[source,java,indent=0] [source,java,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
@ -5219,9 +5223,39 @@ counterparts inside a Spring `@Configuration` class. The difference is that `@Co
classes are not enhanced with CGLIB to intercept the invocation of methods and fields. classes are not enhanced with CGLIB to intercept the invocation of methods and fields.
CGLIB proxying is the means by which invoking methods or fields within `@Bean` methods CGLIB proxying is the means by which invoking methods or fields within `@Bean` methods
in `@Configuration` classes creates bean metadata references to collaborating objects; in `@Configuration` classes creates bean metadata references to collaborating objects;
such methods are __not__ invoked with normal Java semantics. In contrast, invoking a such methods are __not__ invoked with normal Java semantics but rather go through the
method or field in an `@Bean` method within a `@Component` class __has__ standard Java container in order to provide the usual lifecycle management and proxying of Spring
semantics. beans even when referring to other beans via programmatic calls to `@Bean` methods.
In contrast, invoking a method or field in an `@Bean` method within a plain `@Component`
class __has__ standard Java semantics, with no special CGLIB processing or other
constraints applying.
[NOTE]
====
You may declare `@Bean` methods as `static`, allowing for them to be called without
creating their containing configuration class as an instance. This makes particular
sense when defining post-processor beans, e.g. of type `BeanFactoryPostProcessor` or
`BeanPostProcessor`, since such beans will get initialized early in the container
lifecycle and should avoid triggering other parts of the configuration at that point.
Note that calls to static `@Bean` methods will never get intercepted by the container,
not even within `@Configuration` classes (see above). This is due to technical
limitations: CGLIB subclassing can only override non-static methods. As a consequence,
a direct call to another `@Bean` method will have standard Java semantics, resulting
in an independent instance being returned straight from the factory method itself.
The Java language visibility of `@Bean` methods does not have an immediate impact on
the resulting bean definition in Spring's container. You may freely declare your
factory methods as you see fit in non-`@Configuration` classes and also for static
methods anywhere. However, regular `@Bean` methods in `@Configuration` classes need
to be overridable, i.e. they must not be declared as `private` or `final`.
Finally, `@Bean` methods will also be discovered on base classes of a given component
or configuration class, as well as on Java 8 default methods declared in interfaces
implemented by the component or configuration class. This allows for a lot of
flexibility in composing complex configuration arrangements, with even multiple
inheritance being possible through Java 8 default methods as of Spring 4.2.
====