Skip to content

Commit f58e1db

Browse files
committed
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
1 parent ca3ba7d commit f58e1db

File tree

2 files changed

+57
-19
lines changed

2 files changed

+57
-19
lines changed

spring-context/src/main/java/org/springframework/context/Lifecycle.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,33 @@ public interface Lifecycle {
5050

5151
/**
5252
* Start this component.
53-
* Should not throw an exception if the component is already running.
54-
* <p>In the case of a container, this will propagate the start signal
55-
* to all components that apply.
53+
* <p>Should not throw an exception if the component is already running.
54+
* <p>In the case of a container, this will propagate the start signal to all
55+
* components that apply.
5656
* @see SmartLifecycle#isAutoStartup()
5757
*/
5858
void start();
5959

6060
/**
61-
* Stop this component, typically in a synchronous fashion, such that
62-
* the component is fully stopped upon return of this method. Consider
63-
* implementing {@link SmartLifecycle} and its {@code stop(Runnable)}
64-
* variant in cases where asynchronous stop behavior is necessary.
61+
* Stop this component, typically in a synchronous fashion, such that the component is
62+
* fully stopped upon return of this method. Consider implementing {@link SmartLifecycle}
63+
* and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary.
64+
* <p>Note that this stop notification is not guaranteed to come before destruction: On
65+
* regular shutdown, {@code Lifecycle} beans will first receive a stop notification before
66+
* the general destruction callbacks are being propagated; however, on hot refresh during a
67+
* context's lifetime or on aborted refresh attempts, only destroy methods will be called.
6568
* <p>Should not throw an exception if the component isn't started yet.
66-
* <p>In the case of a container, this will propagate the stop signal
67-
* to all components that apply.
69+
* <p>In the case of a container, this will propagate the stop signal to all components
70+
* that apply.
6871
* @see SmartLifecycle#stop(Runnable)
72+
* @see org.springframework.beans.factory.DisposableBean#destroy()
6973
*/
7074
void stop();
7175

7276
/**
7377
* Check whether this component is currently running.
74-
* <p>In the case of a container, this will return {@code true}
75-
* only if <i>all</i> components that apply are currently running.
78+
* <p>In the case of a container, this will return {@code true} only if <i>all</i>
79+
* components that apply are currently running.
7680
* @return whether the component is currently running
7781
*/
7882
boolean isRunning();

src/asciidoc/core-beans.adoc

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,7 @@ unnecessarily couples the code to Spring. Alternatively, use
28492849
the <<beans-postconstruct-and-predestroy-annotations, `@PostConstruct`>> annotation or
28502850
specify a POJO initialization method. In the case of XML-based configuration metadata,
28512851
you use the `init-method` attribute to specify the name of the method that has a void
2852-
no-argument signature. With Java config you use the `initMethod` attribute of `@Bean`,
2852+
no-argument signature. With Java config, you use the `initMethod` attribute of `@Bean`,
28532853
see <<beans-java-lifecycle-callbacks>>. For example, the following:
28542854

28552855
[source,xml,indent=0]
@@ -2909,8 +2909,8 @@ It is recommended that you do not use the `DisposableBean` callback interface be
29092909
unnecessarily couples the code to Spring. Alternatively, use
29102910
the <<beans-postconstruct-and-predestroy-annotations, `@PreDestroy`>> annotation or
29112911
specify a generic method that is supported by bean definitions. With XML-based
2912-
configuration metadata, you use the `destroy-method` attribute on the `<bean/>`. With
2913-
Java config you use the `destroyMethod` attribute of `@Bean`, see
2912+
configuration metadata, you use the `destroy-method` attribute on the `<bean/>`.
2913+
With Java config, you use the `destroyMethod` attribute of `@Bean`, see
29142914
<<beans-java-lifecycle-callbacks>>. For example, the following definition:
29152915

29162916
[source,xml,indent=0]
@@ -3122,6 +3122,10 @@ Note that the regular `org.springframework.context.Lifecycle` interface is just
31223122
contract for explicit start/stop notifications and does NOT imply auto-startup at context
31233123
refresh time. Consider implementing `org.springframework.context.SmartLifecycle` instead
31243124
for fine-grained control over auto-startup of a specific bean (including startup phases).
3125+
Also, please note that stop notifications are not guaranteed to come before destruction:
3126+
On regular shutdown, all `Lifecycle` beans will first receive a stop notification before
3127+
the general destruction callbacks are being propagated; however, on hot refresh during a
3128+
context's lifetime or on aborted refresh attempts, only destroy methods will be called.
31253129
====
31263130

31273131
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
51285132
[[beans-factorybeans-annotations]]
51295133
=== Defining bean metadata within components
51305134
Spring components can also contribute bean definition metadata to the container. You do
5131-
this with the same `@Bean` annotation used to define bean metadata within
5132-
`@Configuration` annotated classes. Here is a simple example:
5135+
this with the same `@Bean` annotation used to define bean metadata within `@Configuration`
5136+
annotated classes. Here is a simple example:
51335137

51345138
[source,java,indent=0]
51355139
[subs="verbatim,quotes"]
@@ -5219,9 +5223,39 @@ counterparts inside a Spring `@Configuration` class. The difference is that `@Co
52195223
classes are not enhanced with CGLIB to intercept the invocation of methods and fields.
52205224
CGLIB proxying is the means by which invoking methods or fields within `@Bean` methods
52215225
in `@Configuration` classes creates bean metadata references to collaborating objects;
5222-
such methods are __not__ invoked with normal Java semantics. In contrast, invoking a
5223-
method or field in an `@Bean` method within a `@Component` class __has__ standard Java
5224-
semantics.
5226+
such methods are __not__ invoked with normal Java semantics but rather go through the
5227+
container in order to provide the usual lifecycle management and proxying of Spring
5228+
beans even when referring to other beans via programmatic calls to `@Bean` methods.
5229+
In contrast, invoking a method or field in an `@Bean` method within a plain `@Component`
5230+
class __has__ standard Java semantics, with no special CGLIB processing or other
5231+
constraints applying.
5232+
5233+
[NOTE]
5234+
====
5235+
You may declare `@Bean` methods as `static`, allowing for them to be called without
5236+
creating their containing configuration class as an instance. This makes particular
5237+
sense when defining post-processor beans, e.g. of type `BeanFactoryPostProcessor` or
5238+
`BeanPostProcessor`, since such beans will get initialized early in the container
5239+
lifecycle and should avoid triggering other parts of the configuration at that point.
5240+
5241+
Note that calls to static `@Bean` methods will never get intercepted by the container,
5242+
not even within `@Configuration` classes (see above). This is due to technical
5243+
limitations: CGLIB subclassing can only override non-static methods. As a consequence,
5244+
a direct call to another `@Bean` method will have standard Java semantics, resulting
5245+
in an independent instance being returned straight from the factory method itself.
5246+
5247+
The Java language visibility of `@Bean` methods does not have an immediate impact on
5248+
the resulting bean definition in Spring's container. You may freely declare your
5249+
factory methods as you see fit in non-`@Configuration` classes and also for static
5250+
methods anywhere. However, regular `@Bean` methods in `@Configuration` classes need
5251+
to be overridable, i.e. they must not be declared as `private` or `final`.
5252+
5253+
Finally, `@Bean` methods will also be discovered on base classes of a given component
5254+
or configuration class, as well as on Java 8 default methods declared in interfaces
5255+
implemented by the component or configuration class. This allows for a lot of
5256+
flexibility in composing complex configuration arrangements, with even multiple
5257+
inheritance being possible through Java 8 default methods as of Spring 4.2.
5258+
====
52255259

52265260

52275261

0 commit comments

Comments
 (0)