@@ -3206,6 +3206,12 @@ beanFactory.registerScope("<emphasis role="bold">thread</emphasis>", threadScope
3206
3206
<interfacename >BeanPostProcessor</interfacename > yourself. For more
3207
3207
information, see <xref linkend =" beans-factory-extension" />.</para >
3208
3208
3209
+ <para >In addition to the initialization and destruction callbacks,
3210
+ Spring-managed objects may also implement the
3211
+ <interfacename >Lifecycle</interfacename > interface so that those
3212
+ objects can participate in the startup and shutdown process as
3213
+ driven by the container's own lifecycle.</para >
3214
+
3209
3215
<para >The lifecycle callback interfaces are described in this
3210
3216
section.</para >
3211
3217
@@ -3447,6 +3453,116 @@ beanFactory.registerScope("<emphasis role="bold">thread</emphasis>", threadScope
3447
3453
</itemizedlist >
3448
3454
</section >
3449
3455
3456
+ <section id =" beans-factory-lifecycle-processor" >
3457
+ <title >Startup and shutdown callbacks</title >
3458
+
3459
+ <para >The <interfacename >Lifecycle</interfacename > interface defines
3460
+ the essential methods for any object that has its own lifecycle
3461
+ requirements (e.g. starts and stops some background process):</para >
3462
+
3463
+ <programlisting language =" java" >public interface Lifecycle {
3464
+
3465
+ void start();
3466
+
3467
+ void stop();
3468
+
3469
+ boolean isRunning();
3470
+
3471
+ }</programlisting >
3472
+
3473
+ <para >Any Spring-managed object may implement that interface. Then,
3474
+ when the ApplicationContext itself starts and stops, it will cascade
3475
+ those calls to all Lifecycle implementations defined within that context.
3476
+ It does this by delegating to a <interfacename >LifecycleProcessor</interfacename >:
3477
+ </para >
3478
+
3479
+ <programlisting language =" java" >public interface LifecycleProcessor extends Lifecycle {
3480
+
3481
+ void onRefresh();
3482
+
3483
+ void onClose();
3484
+
3485
+ }</programlisting >
3486
+
3487
+ <para >Notice that the <interfacename >LifecycleProcessor</interfacename >
3488
+ is itself an extension of the <interfacename >Lifecycle</interfacename >
3489
+ interface. It also adds two other methods for reacting to the context
3490
+ being refreshed and closed.</para >
3491
+
3492
+ <para >The order of startup and shutdown invocations can be important.
3493
+ If a "depends-on" relationship exists between any two objects, the
3494
+ dependent side will start <emphasis >after</emphasis > its dependency,
3495
+ and it will stop <emphasis >before</emphasis > its dependency. However,
3496
+ at times the direct dependencies are unknown. You may only know that
3497
+ objects of a certain type should start prior to objects of another
3498
+ type. In those cases, the <interfacename >SmartLifecycle</interfacename >
3499
+ interface defines another option, namely the <methodname >getPhase()</methodname >
3500
+ method as defined on its super-interface, <interfacename >Phased</interfacename >.
3501
+ </para >
3502
+
3503
+ <programlisting language =" java" >public interface Phased {
3504
+
3505
+ int getPhase();
3506
+
3507
+ }
3508
+
3509
+
3510
+ public interface SmartLifecycle extends Lifecycle, Phased {
3511
+
3512
+ boolean isAutoStartup();
3513
+
3514
+ void stop(Runnable callback);
3515
+
3516
+ }</programlisting >
3517
+
3518
+ <para >When starting, the objects with the lowest phase start first, and
3519
+ when stopping, the reverse order is followed. Therefore, an object that
3520
+ implements <interfacename >SmartLifecycle</interfacename > and whose getPhase()
3521
+ method returns <literal >Integer.MIN_VALUE</literal > would be among the first
3522
+ to start and the last to stop. At the other end of the spectrum, a phase
3523
+ value of <literal >Integer.MAX_VALUE</literal > would indicate that the
3524
+ object should be started last and stopped first (likely because it
3525
+ depends on other processes to be running). When considering the phase value,
3526
+ it's also important to know that the default phase for any "normal"
3527
+ <interfacename >Lifecycle</interfacename > object that does not implement
3528
+ <interfacename >SmartLifecycle</interfacename > would be 0. Therefore, any
3529
+ negative phase value would indicate that an object should start before
3530
+ those standard components (and stop after them), and vice versa for any
3531
+ positive phase value.</para >
3532
+
3533
+ <para >As you can see the stop method defined by <interfacename >SmartLifecycle</interfacename >
3534
+ accepts a callback. Any implementation <emphasis >must</emphasis > invoke that
3535
+ callback's run() method after that implementation's shutdown process is complete.
3536
+ That enables asynchronous shutdown where necessary since the default
3537
+ implementation of the <interfacename >LifecycleProcessor</interfacename >
3538
+ interface, <classname >DefaultLifecycleProcessor</classname >, will wait
3539
+ up to its timeout value for the group of objects within each phase to
3540
+ invoke that callback. The default per-phase timeout is 30 seconds. You
3541
+ can override the default lifecycle processor instance by defining a bean
3542
+ named "lifecycleProcessor" within the context. If you only want to modify
3543
+ the timeout, then defining the following would be sufficient:</para >
3544
+
3545
+ <programlisting language =" xml" ><![CDATA[ <bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
3546
+ <!-- timeout value in milliseconds -->
3547
+ <property name="timeoutPerShutdownPhase" value="10000"/>
3548
+ </bean>]]> </programlisting >
3549
+
3550
+ <para >As mentioned, the <interfacename >LifecycleProcessor</interfacename > interface
3551
+ defines callback methods for the refreshing and closing of the context as well. The
3552
+ latter will simply drive the shutdown process as if stop() had been called explicitly,
3553
+ but it will happen when the context is closing. The 'refresh' callback on the other
3554
+ hand enables another feature of <interfacename >SmartLifecycle</interfacename > beans.
3555
+ When the context is refreshed (after all objects have been instantiated and initialized),
3556
+ that callback will be invoked, and at that point the default lifecycle processor will
3557
+ check the boolean value returned by each <interfacename >SmartLifecycle</interfacename >
3558
+ object's <methodname >isAutoStartup()</methodname > method. If "true", then that object
3559
+ will be started at that point rather than waiting for an explicit invocation of the
3560
+ context's or its own start() method (unlike the context refresh, the context start does
3561
+ not happen automatically for a standard context implementation). The "phase" value as
3562
+ well as any "depends-on" relationships will determine the startup order in the same way
3563
+ as described above.</para >
3564
+ </section >
3565
+
3450
3566
<section id =" beans-factory-shutdown" >
3451
3567
<title >Shutting down the Spring IoC container gracefully in non-web
3452
3568
applications</title >
0 commit comments