From 6d226326c942843e454d9f261e296a5120672ef5 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Fri, 21 Sep 2018 16:06:09 -0500 Subject: [PATCH] Editing pass for the integration and languages chapters. I edited for spelling, puncutation, grammar, usage, and corporate voice. I also added a bunch of cross-references and links to the Javadoc. I also corrected the rendering problems that I had accidentally created in previous commits (because I was adjusting headings and adding callouts to listings. --- src/docs/asciidoc/data-access.adoc | 9 +- src/docs/asciidoc/integration-appendix.adoc | 164 +- src/docs/asciidoc/integration.adoc | 4867 +++++++++-------- .../asciidoc/languages/dynamic-languages.adoc | 513 +- src/docs/asciidoc/languages/groovy.adoc | 6 +- src/docs/asciidoc/languages/kotlin.adoc | 514 +- src/docs/asciidoc/web/webflux-webclient.adoc | 9 +- src/docs/asciidoc/web/webflux.adoc | 12 +- 8 files changed, 3348 insertions(+), 2746 deletions(-) diff --git a/src/docs/asciidoc/data-access.adoc b/src/docs/asciidoc/data-access.adoc index 0f04b671f4..5117afbb3d 100644 --- a/src/docs/asciidoc/data-access.adoc +++ b/src/docs/asciidoc/data-access.adoc @@ -6805,12 +6805,13 @@ preamble of the XML configuration file. The following example shows how to do so <1> + xmlns:oxm="http://www.springframework.org/schema/oxm" <1> + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd"> <2> ---- <1> Reference the `oxm` schema. +<2> Specify the `oxm` schema location. ==== Currently, the schema makes the following elements available: diff --git a/src/docs/asciidoc/integration-appendix.adoc b/src/docs/asciidoc/integration-appendix.adoc index 0f5628e183..19b77c0f28 100644 --- a/src/docs/asciidoc/integration-appendix.adoc +++ b/src/docs/asciidoc/integration-appendix.adoc @@ -1,8 +1,6 @@ = Appendix - - [[xsd-schemas]] == XML Schemas @@ -11,15 +9,16 @@ This part of the appendix lists XML schemas related to integration technologies. [[xsd-schemas-jee]] -=== The jee schema +=== The `jee` Schema -The `jee` tags deal with Java EE (Java Enterprise Edition)-related configuration issues, +The `jee` elements deal with issues related to Java EE (Java Enterprise Edition) configuration, such as looking up a JNDI object and defining EJB references. -To use the tags in the `jee` schema, you need to have the following preamble at the top -of your Spring XML configuration file; the text in the following snippet references the -correct schema so that the tags in the `jee` namespace are available to you. +To use the elements in the `jee` schema, you need to have the following preamble at the top +of your Spring XML configuration file. The text in the following snippet references the +correct schema so that the elements in the `jee` namespace are available to you: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -28,17 +27,22 @@ correct schema so that the tags in the `jee` namespace are available to you. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" __xmlns:jee="http://www.springframework.org/schema/jee"__ xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd - __http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__> + __http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"__> + ---- +==== + [[xsd-schemas-jee-jndi-lookup]] ==== (simple) -Before... +The following example shows how to use JNDI to look up a data source without the `jee` +schema: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -50,9 +54,12 @@ Before... ---- +==== -After... +The following example shows how to use JNDI to look up a data source with the `jee` +schema: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -63,13 +70,17 @@ After... ---- +==== + [[xsd-schemas-jee-jndi-lookup-environment-single]] -==== (with single JNDI environment setting) +==== `` (with Single JNDI Environment Setting) -Before... +The following example shows how to use JNDI to look up an environment variable without +`jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -77,28 +88,31 @@ Before... - bar + pong ---- +==== -After... +The following example shows how to use JNDI to look up an environment variable with `jee`: [source,xml,indent=0] [subs="verbatim,quotes"] ---- - foo=bar + ping=pong ---- [[xsd-schemas-jee-jndi-lookup-evironment-multiple]] -==== (with multiple JNDI environment settings) +==== `` (with Multiple JNDI Environment Settings) -Before... +The following example shows how to use JNDI to look up multiple environment variables +without `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -106,33 +120,39 @@ Before... - bar + song pong ---- +==== -After... +The following example shows how to use JNDI to look up multiple environment variables with +`jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - foo=bar + sing=song ping=pong ---- +==== [[xsd-schemas-jee-jndi-lookup-complex]] -==== (complex) +==== `` (Complex) -Before... +The following example shows how to use JNDI to look up a data source and a number of +different properties without `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -141,13 +161,16 @@ Before... - - + + ---- +==== -After... +The following example shows how to use JNDI to look up a data source and a number of +different properties with `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -156,18 +179,22 @@ After... cache="true" resource-ref="true" lookup-on-startup="false" - expected-type="com.myapp.DefaultFoo" - proxy-interface="com.myapp.Foo"/> + expected-type="com.myapp.DefaultThing" + proxy-interface="com.myapp.Thing"/> ---- +==== + [[xsd-schemas-jee-local-slsb]] -==== (simple) +==== `` (Simple) -The `` tag configures a reference to an EJB Stateless SessionBean. +The `` element configures a reference to a local EJB Stateless SessionBean. -Before... +The following example shows how to configures a reference to a local EJB Stateless +SessionBean without `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -177,35 +204,49 @@ Before... ---- +==== -After... +The following example shows how to configures a reference to a local EJB Stateless +SessionBean with `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== + [[xsd-schemas-jee-local-slsb-complex]] -==== (complex) +==== `` (Complex) + +The `` element configures a reference to a local EJB Stateless SessionBean. + +The following example shows how to configures a reference to a local EJB Stateless +SessionBean and a number of properties without `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + ---- +==== -After... +The following example shows how to configures a reference to a local EJB Stateless +SessionBean and a number of properties with `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -216,16 +257,19 @@ After... lookup-home-on-startup="true" resource-ref="true"> ---- +==== [[xsd-schemas-jee-remote-slsb]] ==== -The `` tag configures a reference to a `remote` EJB Stateless +The `` element configures a reference to a `remote` EJB Stateless SessionBean. -Before... +The following example shows how to configures a reference to a remote EJB Stateless +SessionBean without `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -240,9 +284,12 @@ Before... ---- +==== -After... +The following example shows how to configures a reference to a remote EJB Stateless +SessionBean with `jee`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -255,24 +302,25 @@ After... home-interface="com.foo.service.RentalService" refresh-home-on-connect-failure="true"> ---- - +==== [[xsd-schemas-jms]] -=== The jms schema +=== The `jms` Schema -The `jms` tags deal with configuring JMS-related beans such as Spring's -<>. These tags are detailed in the +The `jms` elements deal with configuring JMS-related beans, such as Spring's +<>. These elements are detailed in the section of the <> entitled <>. Please do consult that chapter for full details on this support -and the `jms` tags themselves. +JMS Namespace Support>>. See that chapter for full details on this support +and the `jms` elements themselves. -In the interest of completeness, to use the tags in the `jms` schema, you need to have -the following preamble at the top of your Spring XML configuration file; the text in the -following snippet references the correct schema so that the tags in the `jms` namespace -are available to you. +In the interest of completeness, to use the elements in the `jms` schema, you need to have +the following preamble at the top of your Spring XML configuration file. The text in the +following snippet references the correct schema so that the elements in the `jms` namespace +are available to you: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -285,28 +333,31 @@ are available to you. ---- +==== + [[xsd-schemas-context-mbe]] -=== +=== Using `` This element is detailed in -<>. +<>. [[xsd-schemas-cache]] -=== The cache schema +=== The `cache` Schema -The `cache` tags can be used to enable support for Spring's `@CacheEvict`, `@CachePut` +You can use the `cache` elements to enable support for Spring's `@CacheEvict`, `@CachePut`, and `@Caching` annotations. It it also supports declarative XML-based caching. See -<> and -<> for details. +<> and +<> for details. -To use the tags in the `cache` schema, you need to have the following preamble at the -top of your Spring XML configuration file; the text in the following snippet references -the correct schema so that the tags in the `cache` namespace are available to you. +To use the elements in the `cache` schema, you need to have the following preamble at the +top of your Spring XML configuration file. The text in the following snippet references +the correct schema so that the elements in the `cache` namespace are available to you: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -319,3 +370,4 @@ the correct schema so that the tags in the `cache` namespace are available to yo ---- +==== diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index a9f1f7d55a..98e05e214f 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -14,40 +14,35 @@ a number of Java EE (and related) technologies. - [[remoting]] -== Remoting and web services using Spring - - - -[[remoting-introduction]] -=== Introduction +== Remoting and Web Services with Spring -Spring features integration classes for remoting support using various technologies. The +Spring features integration classes for remoting support with various technologies. The remoting support eases the development of remote-enabled services, implemented by your usual (Spring) POJOs. Currently, Spring supports the following remoting technologies: -* __Remote Method Invocation (RMI)__. Through the use of the `RmiProxyFactoryBean` and - the `RmiServiceExporter` Spring supports both traditional RMI (with `java.rmi.Remote` - interfaces and `java.rmi.RemoteException`) and transparent remoting via RMI invokers +* *Remote Method Invocation (RMI)*: Through the use of `RmiProxyFactoryBean` and + `RmiServiceExporter`, Spring supports both traditional RMI (with `java.rmi.Remote` + interfaces and `java.rmi.RemoteException`) and transparent remoting through RMI invokers (with any Java interface). -* __Spring's HTTP invoker__. Spring provides a special remoting strategy which allows - for Java serialization via HTTP, supporting any Java interface (just like the RMI - invoker). The corresponding support classes are `HttpInvokerProxyFactoryBean` and +* *Spring's HTTP invoker*: Spring provides a special remoting strategy that allows + for Java serialization though HTTP, supporting any Java interface (as the RMI + invoker does). The corresponding support classes are `HttpInvokerProxyFactoryBean` and `HttpInvokerServiceExporter`. -* __Hessian__. By using Spring's `HessianProxyFactoryBean` and the - `HessianServiceExporter` you can transparently expose your services using the +* *Hessian*: By using Spring's `HessianProxyFactoryBean` and the + `HessianServiceExporter`, you can transparently expose your services through the lightweight binary HTTP-based protocol provided by Caucho. -* __JAX-WS__. Spring provides remoting support for web services via JAX-WS (the +* *JAX-WS*: Spring provides remoting support for web services through JAX-WS (the successor of JAX-RPC, as introduced in Java EE 5 and Java 6). -* __JMS__. Remoting using JMS as the underlying protocol is supported via the +* *JMS*: Remoting by using JMS as the underlying protocol is supported through the `JmsInvokerServiceExporter` and `JmsInvokerProxyFactoryBean` classes. -* __AMQP__. Remoting using AMQP as the underlying protocol is supported by the Spring +* *AMQP*: Remoting by using AMQP as the underlying protocol is supported by the Spring AMQP project. -While discussing the remoting capabilities of Spring, we'll use the following domain +While discussing the remoting capabilities of Spring, we use the following domain model and corresponding services: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -94,34 +89,38 @@ model and corresponding services: } ---- +==== -We will start exposing the service to a remote client by using RMI and talk a bit about -the drawbacks of using RMI. We'll then continue to show an example using Hessian as the +This section starts by exposing the service to a remote client by using RMI and talk a bit about +the drawbacks of using RMI. It then continues with an example that uses Hessian as the protocol. [[remoting-rmi]] -=== Exposing services using RMI +=== Exposing Services by Using RMI -Using Spring's support for RMI, you can transparently expose your services through the +By using Spring's support for RMI, you can transparently expose your services through the RMI infrastructure. After having this set up, you basically have a configuration similar to remote EJBs, except for the fact that there is no standard support for security context propagation or remote transaction propagation. Spring does provide hooks for -such additional invocation context when using the RMI invoker, so you can for example -plug in security frameworks or custom security credentials here. +such additional invocation context when you use the RMI invoker, so you can, for example, +plug in security frameworks or custom security credentials. + [[remoting-rmi-server]] -==== Exporting the service using the RmiServiceExporter +==== Exporting the Service by Using `RmiServiceExporter` Using the `RmiServiceExporter`, we can expose the interface of our AccountService object as RMI object. The interface can be accessed by using `RmiProxyFactoryBean`, or via plain RMI in case of a traditional RMI service. The `RmiServiceExporter` explicitly supports the exposing of any non-RMI services via RMI invokers. -Of course, we first have to set up our service in the Spring container: +We first have to set up our service in the Spring container. +The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -129,9 +128,12 @@ Of course, we first have to set up our service in the Spring container: ---- +==== -Next we'll have to expose our service using the `RmiServiceExporter`: +Next, we have to expose our service by using `RmiServiceExporter`. +The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -144,25 +146,26 @@ Next we'll have to expose our service using the `RmiServiceExporter`: ---- +==== -As you can see, we're overriding the port for the RMI registry. Often, your application -server also maintains an RMI registry and it is wise to not interfere with that one. -Furthermore, the service name is used to bind the service under. So right now, the -service will be bound at `'rmi://HOST:1199/AccountService'`. We'll use the URL later on +In the preceding example, we override the port for the RMI registry. Often, your application +server also maintains an RMI registry, and it is wise to not interfere with that one. +Furthermore, the service name is used to bind the service. So, in the preceding example, the +service is bound at `'rmi://HOST:1199/AccountService'`. We use this URL later on to link in the service at the client side. -[NOTE] -==== -The `servicePort` property has been omitted (it defaults to 0). This means that an -anonymous port will be used to communicate with the service. -==== +NOTE: The `servicePort` property has been omitted (it defaults to 0). This means that an +anonymous port is used to communicate with the service. + [[remoting-rmi-client]] -==== Linking in the service at the client +==== Linking in the Service at the Client -Our client is a simple object using the `AccountService` to manage accounts: +Our client is a simple object that uses the `AccountService` to manage accounts, +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -178,10 +181,12 @@ Our client is a simple object using the `AccountService` to manage accounts: } ---- +==== -To link in the service on the client, we'll create a separate Spring container, -containing the simple object and the service linking configuration bits: +To link in the service on the client, we create a separate Spring container, +to contain the following simple object and the service linking configuration bits: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -194,28 +199,31 @@ containing the simple object and the service linking configuration bits: ---- +==== -That's all we need to do to support the remote account service on the client. Spring -will transparently create an invoker and remotely enable the account service through the -`RmiServiceExporter`. At the client we're linking it in using the `RmiProxyFactoryBean`. +That is all we need to do to support the remote account service on the client. Spring +transparently creates an invoker and remotely enables the account service through the +`RmiServiceExporter`. At the client, we link it in by using the `RmiProxyFactoryBean`. [[remoting-caucho-protocols]] -=== Using Hessian to remotely call services via HTTP +=== Using Hessian to Remotely Call Services through HTTP + +Hessian offers a binary HTTP-based remoting protocol. It is developed by Caucho, and you can find more +information about Hessian itself at http://www.caucho.com[]. -Hessian offers a binary HTTP-based remoting protocol. It is developed by Caucho and more -information about Hessian itself can be found at http://www.caucho.com[]. [[remoting-caucho-protocols-hessian]] -==== Wiring up the DispatcherServlet for Hessian and co. +==== Wiring up `DispatcherServlet` for Hessian -Hessian communicates via HTTP and does so using a custom servlet. Using Spring's -`DispatcherServlet` principles, as known from Spring Web MVC usage, you can easily wire -up such a servlet exposing your services. First we'll have to create a new servlet in -your application (this is an excerpt from `'web.xml'`): +Hessian communicates through HTTP and does so by using a custom servlet. By using Spring's +`DispatcherServlet` principles (see <>), we can wire +up such a servlet to expose your services. First, we have to create a new servlet in +our application, as shown in the following excerpt from `web.xml`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -230,25 +238,28 @@ your application (this is an excerpt from `'web.xml'`): /remoting/* ---- +==== -You're probably familiar with Spring's `DispatcherServlet` principles and if so, you -know that now you'll have to create a Spring container configuration resource named -`'remoting-servlet.xml'` (after the name of your servlet) in the `'WEB-INF'` directory. -The application context will be used in the next section. +If you are familiar with Spring's `DispatcherServlet` principles, you probably +know that now you have to create a Spring container configuration resource named +`remoting-servlet.xml` (after the name of your servlet) in the `WEB-INF` directory. +The application context is used in the next section. + +Alternatively, consider the use of Spring's simpler `HttpRequestHandlerServlet`. Doing so +lets you embed the remote exporter definitions in your root application context (by +default, in `WEB-INF/applicationContext.xml`), with individual servlet definitions +pointing to specific exporter beans. In this case, each servlet name needs to match the bean name of +its target exporter. -Alternatively, consider the use of Spring's simpler `HttpRequestHandlerServlet`. This -allows you to embed the remote exporter definitions in your root application context (by -default in `'WEB-INF/applicationContext.xml'`), with individual servlet definitions -pointing to specific exporter beans. Each servlet name needs to match the bean name of -its target exporter in this case. [[remoting-caucho-protocols-hessian-server]] -==== Exposing your beans by using the HessianServiceExporter +==== Exposing Your Beans by Using `HessianServiceExporter` -In the newly created application context called `remoting-servlet.xml`, we'll create a -`HessianServiceExporter` exporting your services: +In the newly created application context called `remoting-servlet.xml`, we create a +`HessianServiceExporter` to export our services, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -261,16 +272,18 @@ In the newly created application context called `remoting-servlet.xml`, we'll cr ---- +==== -Now we're ready to link in the service at the client. No explicit handler mapping is -specified, mapping request URLs onto services, so `BeanNameUrlHandlerMapping` will be -used: Hence, the service will be exported at the URL indicated through its bean name -within the containing ``DispatcherServlet``'s mapping (as defined above): -`'http://HOST:8080/remoting/AccountService'`. +Now we are ready to link in the service at the client. No explicit handler mapping is +specified (to map request URLs onto services), so we use `BeanNameUrlHandlerMapping` +used. Hence, the service is exported at the URL indicated through its bean name +within the containing `DispatcherServlet` instance's mapping (as defined earlier): +`http://HOST:8080/remoting/AccountService`. -Alternatively, create a `HessianServiceExporter` in your root application context (e.g. -in `'WEB-INF/applicationContext.xml'`): +Alternatively, you can create a `HessianServiceExporter` in your root application context (for example, +in `WEB-INF/applicationContext.xml`), as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -279,12 +292,14 @@ in `'WEB-INF/applicationContext.xml'`): ---- +==== -In the latter case, define a corresponding servlet for this exporter in `'web.xml'`, -with the same end result: The exporter getting mapped to the request path +In the latter case, you should define a corresponding servlet for this exporter in `web.xml`, +with the same end result: The exporter gets mapped to the request path at `/remoting/AccountService`. Note that the servlet name needs to match the bean name of -the target exporter. +the target exporter. The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -298,16 +313,19 @@ the target exporter. /remoting/AccountService ---- +==== + [[remoting-caucho-protocols-hessian-client]] -==== Linking in the service on the client +==== Linking in the Service on the Client -Using the `HessianProxyFactoryBean` we can link in the service at the client. The same -principles apply as with the RMI example. We'll create a separate bean factory or -application context and mention the following beans where the `SimpleObject` is using -the `AccountService` to manage accounts: +By using the `HessianProxyFactoryBean`, we can link in the service at the client. The same +principles apply as with the RMI example. We create a separate bean factory or +application context and mention the following beans where the `SimpleObject` is by using +the `AccountService` to manage accounts, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -320,17 +338,20 @@ the `AccountService` to manage accounts: ---- +==== + [[remoting-caucho-protocols-security]] -==== Applying HTTP basic authentication to a service exposed through Hessian +==== Applying HTTP Basic Authentication to a Service Exposed through Hessian One of the advantages of Hessian is that we can easily apply HTTP basic authentication, because both protocols are HTTP-based. Your normal HTTP server security mechanism can -easily be applied through using the `web.xml` security features, for example. Usually, -you don't use per-user security credentials here, but rather shared credentials defined -at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`). +be applied through using the `web.xml` security features, for example. Usually, +you need not use per-user security credentials here. Rather, you can use shared credentials that you define +at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`), as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -343,64 +364,64 @@ at the `HessianProxyFactoryBean` level (similar to a JDBC `DataSource`). ---- +==== -This is an example where we explicitly mention the `BeanNameUrlHandlerMapping` and set -an interceptor allowing only administrators and operators to call the beans mentioned in +In the preceding example, we explicitly mention the `BeanNameUrlHandlerMapping` and set +an interceptor, to let only administrators and operators call the beans mentioned in this application context. -[NOTE] -==== -Of course, this example doesn't show a flexible kind of security infrastructure. For +NOTE: The preceding example does not show a flexible kind of security infrastructure. For more options as far as security is concerned, have a look at the Spring Security project -at http://projects.spring.io/spring-security/[]. -==== +at http://projects.spring.io/spring-security/. [[remoting-httpinvoker]] -=== Exposing services using HTTP invokers +=== Exposing Services by Using HTTP Invokers -As opposed to Hessian, which are both lightweight protocols using their own slim -serialization mechanisms, Spring HTTP invokers use the standard Java serialization +As opposed to Hessian, Spring HTTP invokers are both lightweight protocols that use their own slim +serialization mechanisms and use the standard Java serialization mechanism to expose services through HTTP. This has a huge advantage if your arguments -and return types are complex types that cannot be serialized using the serialization -mechanisms Hessian uses (refer to the next section for more considerations when -choosing a remoting technology). +and return types are complex types that cannot be serialized by using the serialization +mechanisms Hessian uses (see the next section for more considerations when +you choose a remoting technology). Under the hood, Spring uses either the standard facilities provided by the JDK or -Apache `HttpComponents` to perform HTTP calls. Use the latter if you need more -advanced and easier-to-use functionality. Refer to +Apache `HttpComponents` to perform HTTP calls. If you need more +advanced and easier-to-use functionality, use the latter. See http://hc.apache.org/httpcomponents-client-ga/[hc.apache.org/httpcomponents-client-ga/] for more information. [WARNING] ==== Be aware of vulnerabilities due to unsafe Java deserialization: -Manipulated input streams could lead to unwanted code execution on the server +Manipulated input streams can lead to unwanted code execution on the server during the deserialization step. As a consequence, do not expose HTTP invoker -endpoints to untrusted clients but rather just between your own services. -In general, we strongly recommend any other message format (e.g. JSON) instead. +endpoints to untrusted clients. Rather, expose them only between your own services. +In general, we strongly recommend using any other message format (such as JSON) instead. If you are concerned about security vulnerabilities due to Java serialization, consider the general-purpose serialization filter mechanism at the core JVM level, -originally developed for JDK 9 but backported to JDK 8, 7 and 6 in the meantime: +originally developed for JDK 9 but backported to JDK 8, 7 and 6 in the meantime. See https://blogs.oracle.com/java-platform-group/entry/incoming_filter_serialization_data_a -http://openjdk.java.net/jeps/290 +and http://openjdk.java.net/jeps/290. ==== + [[remoting-httpinvoker-server]] -==== Exposing the service object +==== Exposing the Service Object -Setting up the HTTP invoker infrastructure for a service object resembles closely the -way you would do the same using Hessian. Just as Hessian support provides the -`HessianServiceExporter`, Spring's HttpInvoker support provides the +Setting up the HTTP invoker infrastructure for a service object closely resembles the +way you would do the same by using Hessian. As Hessian support provides +`HessianServiceExporter`, Spring's HttpInvoker support provides `org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter`. -To expose the `AccountService` (mentioned above) within a Spring Web MVC +To expose the `AccountService` (mentioned earlier) within a Spring Web MVC `DispatcherServlet`, the following configuration needs to be in place in the -dispatcher's application context: +dispatcher's application context, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -409,13 +430,15 @@ dispatcher's application context: ---- +==== -Such an exporter definition will be exposed through the ``DispatcherServlet``'s standard -mapping facilities, as explained in the section on Hessian. +Such an exporter definition is exposed through the `DispatcherServlet` instance's standard +mapping facilities, as explained in <>. -Alternatively, create an `HttpInvokerServiceExporter` in your root application context -(e.g. in `'WEB-INF/applicationContext.xml'`): +Alternatively, you can create an `HttpInvokerServiceExporter` in your root application context +(for example, in `'WEB-INF/applicationContext.xml'`), as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -424,10 +447,12 @@ Alternatively, create an `HttpInvokerServiceExporter` in your root application c ---- +==== -In addition, define a corresponding servlet for this exporter in `'web.xml'`, with the -servlet name matching the bean name of the target exporter: +In addition, you can define a corresponding servlet for this exporter in `web.xml`, with the +servlet name matching the bean name of the target exporter, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -441,15 +466,19 @@ servlet name matching the bean name of the target exporter: /remoting/AccountService ---- +==== + [[remoting-httpinvoker-client]] -==== Linking in the service at the client +==== Linking in the Service at the Client Again, linking in the service from the client much resembles the way you would do it -when using Hessian. Using a proxy, Spring will be able to translate your calls to -HTTP POST requests to the URL pointing to the exported service. +when you use Hessian. By using a proxy, Spring can translate your calls to +HTTP POST requests to the URL that points to the exported service. The following example +shows how to configure this arrangement: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -458,11 +487,14 @@ HTTP POST requests to the URL pointing to the exported service. ---- +==== -As mentioned before, you can choose what HTTP client you want to use. By default, the +As mentioned earlier, you can choose what HTTP client you want to use. By default, the `HttpInvokerProxy` uses the JDK's HTTP functionality, but you can also use the Apache -`HttpComponents` client by setting the `httpInvokerRequestExecutor` property: +`HttpComponents` client by setting the `httpInvokerRequestExecutor` property. +The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -470,32 +502,36 @@ As mentioned before, you can choose what HTTP client you want to use. By default ---- +==== [[remoting-web-services]] -=== Web services +=== Web Services -Spring provides full support for standard Java web services APIs: +Spring provides full support for the standard Java web services APIs: * Exposing web services using JAX-WS * Accessing web services using JAX-WS In addition to stock support for JAX-WS in Spring Core, the Spring portfolio also -features http://www.springframework.org/spring-ws[Spring Web Services], a solution for -contract-first, document-driven web services - highly recommended for building modern, +features http://www.springframework.org/spring-ws[Spring Web Services], which is a solution for +contract-first, document-driven web services -- highly recommended for building modern, future-proof web services. + [[remoting-web-services-jaxws-export-servlet]] -==== Exposing servlet-based web services using JAX-WS +==== Exposing Servlet-based Web Services by Using JAX-WS -Spring provides a convenient base class for JAX-WS servlet endpoint implementations - -`SpringBeanAutowiringSupport`. To expose our `AccountService` we extend Spring's +Spring provides a convenient base class for JAX-WS servlet endpoint implementations: +`SpringBeanAutowiringSupport`. To expose our `AccountService`, we extend Spring's `SpringBeanAutowiringSupport` class and implement our business logic here, usually -delegating the call to the business layer. We'll simply use Spring's `@Autowired` -annotation for expressing such dependencies on Spring-managed beans. +delegating the call to the business layer. We use Spring's `@Autowired` +annotation to express such dependencies on Spring-managed beans. The following example +shows our class that extends `SpringBeanAutowiringSupport`: +==== [source,java,indent=0] ---- /** @@ -535,28 +571,32 @@ annotation for expressing such dependencies on Spring-managed beans. } ---- +==== Our `AccountServiceEndpoint` needs to run in the same web application as the Spring context to allow for access to Spring's facilities. This is the case by default in Java EE 5 environments, using the standard contract for JAX-WS servlet endpoint deployment. -See Java EE 5 web service tutorials for details. +See the various Java EE 5 web service tutorials for details. + [[remoting-web-services-jaxws-export-standalone]] -==== Exporting standalone web services using JAX-WS +==== Exporting Standalone Web Services by Using JAX-WS The built-in JAX-WS provider that comes with Oracle's JDK supports exposure of web -services using the built-in HTTP server that's included in the JDK as well. Spring's -`SimpleJaxWsServiceExporter` detects all `@WebService` annotated beans in the Spring -application context, exporting them through the default JAX-WS server (the JDK HTTP +services by using the built-in HTTP server that is also included in the JDK. Spring's +`SimpleJaxWsServiceExporter` detects all `@WebService`-annotated beans in the Spring +application context and exports them through the default JAX-WS server (the JDK HTTP server). In this scenario, the endpoint instances are defined and managed as Spring beans -themselves; they will be registered with the JAX-WS engine but their lifecycle will be -up to the Spring application context. This means that Spring functionality like explicit -dependency injection may be applied to the endpoint instances. Of course, -annotation-driven injection through `@Autowired` will work as well. +themselves. They are registered with the JAX-WS engine, but their lifecycle is +up to the Spring application context. This means that you can apply Spring functionality (such as explicit +dependency injection) to the endpoint instances. +Annotation-driven injection through `@Autowired` works as well. +The following example shows how to define these beans: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -570,12 +610,14 @@ annotation-driven injection through `@Autowired` will work as well. ... ---- +==== -The `AccountServiceEndpoint` may derive from Spring's `SpringBeanAutowiringSupport` but -doesn't have to since the endpoint is a fully Spring-managed bean here. This means that -the endpoint implementation may look like as follows, without any superclass declared - -and Spring's `@Autowired` configuration annotation still being honored: +The `AccountServiceEndpoint` can but does not have to derive from Spring's `SpringBeanAutowiringSupport`, +since the endpoint in this example is a fully Spring-managed bean. This means that +the endpoint implementation can be as follows (without any superclass declared -- +and Spring's `@Autowired` configuration annotation is still honored): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -597,59 +639,67 @@ and Spring's `@Autowired` configuration annotation still being honored: } ---- +==== + [[remoting-web-services-jaxws-export-ri]] -==== Exporting web services using the JAX-WS RI's Spring support +==== Exporting Web Services by Using JAX-WS RI's Spring Support Oracle's JAX-WS RI, developed as part of the GlassFish project, ships Spring support as part of its JAX-WS Commons project. This allows for defining JAX-WS endpoints as -Spring-managed beans, similar to the standalone mode discussed in the previous section - -but this time in a Servlet environment. __Note that this is not portable in a Java EE 5 -environment; it is mainly intended for non-EE environments such as Tomcat, embedding the -JAX-WS RI as part of the web application.__ - -The difference to the standard style of exporting servlet-based endpoints is that the -lifecycle of the endpoint instances themselves will be managed by Spring here, and that -there will be only one JAX-WS servlet defined in `web.xml`. With the standard Java EE 5 -style (as illustrated above), you'll have one servlet definition per service endpoint, +Spring-managed beans, similar to the standalone mode discussed in the <> -- +but this time in a Servlet environment. + +NOTE: This is not portable in a Java EE 5 +environment. It is mainly intended for non-EE environments, such as Tomcat, that embed the +JAX-WS RI as part of the web application. + +The differences from the standard style of exporting servlet-based endpoints are that the +lifecycle of the endpoint instances themselves are managed by Spring and that +there is only one JAX-WS servlet defined in `web.xml`. With the standard Java EE 5 +style (as shown earlier), you have one servlet definition per service endpoint, with each endpoint typically delegating to Spring beans (through the use of -`@Autowired`, as shown above). +`@Autowired`, as shown earlier). -Check out https://jax-ws-commons.java.net/spring/[https://jax-ws-commons.java.net/spring/] +See https://jax-ws-commons.java.net/spring/[https://jax-ws-commons.java.net/spring/] for details on setup and usage style. + [[remoting-web-services-jaxws-access]] -==== Accessing web services using JAX-WS +==== Accessing Web Services by Using JAX-WS Spring provides two factory beans to create JAX-WS web service proxies, namely -`LocalJaxWsServiceFactoryBean` and `JaxWsPortProxyFactoryBean`. The former can only -return a JAX-WS service class for us to work with. The latter is the full-fledged -version that can return a proxy that implements our business service interface. In this -example we use the latter to create a proxy for the `AccountService` endpoint (again): +`LocalJaxWsServiceFactoryBean` and `JaxWsPortProxyFactoryBean`. The former can +return only a JAX-WS service class for us to work with. The latter is the full-fledged +version that can return a proxy that implements our business service interface. In the following +example, we use `JaxWsPortProxyFactoryBean` to create a proxy for the `AccountService` endpoint (again): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + <1> ---- +<1> Where `serviceInterface` is our business interface that the clients use. +==== -Where `serviceInterface` is our business interface the clients will use. -`wsdlDocumentUrl` is the URL for the WSDL file. Spring needs this a startup time to -create the JAX-WS Service. `namespaceUri` corresponds to the targetNamespace in the +`wsdlDocumentUrl` is the URL for the WSDL file. Spring needs this at startup time to +create the JAX-WS Service. `namespaceUri` corresponds to the `targetNamespace` in the .wsdl file. `serviceName` corresponds to the service name in the .wsdl file. `portName` corresponds to the port name in the .wsdl file. -Accessing the web service is now very easy as we have a bean factory for it that will -expose it as `AccountService` interface. We can wire this up in Spring: +Accessing the web service is easy, as we have a bean factory for it that +exposes it as an interface called `AccountService`. The following example shows how we can wire this up in Spring: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -658,9 +708,12 @@ expose it as `AccountService` interface. We can wire this up in Spring: ---- +==== -From the client code we can access the web service just as if it was a normal class: +From the client code, we can access the web service as if it were a normal class, +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -677,31 +730,30 @@ From the client code we can access the web service just as if it was a normal cl } } ---- - -[NOTE] ==== -The above is slightly simplified in that JAX-WS requires endpoint interfaces + +NOTE: The above is slightly simplified in that JAX-WS requires endpoint interfaces and implementation classes to be annotated with `@WebService`, `@SOAPBinding` etc annotations. This means that you cannot (easily) use plain Java interfaces and implementation classes as JAX-WS endpoint artifacts; you need to annotate them accordingly first. Check the JAX-WS documentation for details on those requirements. -==== [[remoting-jms]] -=== JMS +=== Exposing Services through JMS -It is also possible to expose services transparently using JMS as the underlying -communication protocol. The JMS remoting support in the Spring Framework is pretty basic -- it sends and receives on the `same thread` and in the __same non-transactional__ -`Session`, and as such throughput will be very implementation dependent. Note that these +You can also expose services transparently by using JMS as the underlying +communication protocol. The JMS remoting support in the Spring Framework is pretty basic. +It sends and receives on the `same thread` and in the same non-transactional +`Session`. As a result, throughput is implementation-dependent. Note that these single-threaded and non-transactional constraints apply only to Spring's JMS -__remoting__ support. See <> for information on Spring's rich support for JMS-based -__messaging__. +remoting support. See <> for information on Spring's rich support for JMS-based +messaging. -The following interface is used on both the server and the client side. +The following interface is used on both the server and the client sides: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -713,9 +765,11 @@ The following interface is used on both the server and the client side. } ---- +==== -The following simple implementation of the above interface is used on the server-side. +The following simple implementation of the preceding interface is used on the server-side: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -729,10 +783,12 @@ The following simple implementation of the above interface is used on the server } ---- +==== -This configuration file contains the JMS-infrastructure beans that are shared on both -the client and server. +The following configuration file contains the JMS-infrastructure beans that are shared on both +the client and server: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -752,14 +808,17 @@ the client and server. ---- +==== + [[remoting-jms-server]] -==== Server-side configuration +==== Server-side Configuration -On the server, you just need to expose the service object using the -`JmsInvokerServiceExporter`. +On the server, you need to expose the service object that uses the +`JmsInvokerServiceExporter`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -802,16 +861,20 @@ On the server, you just need to expose the service object using the } ---- +==== + [[remoting-jms-client]] -==== Client-side configuration +==== Client-side Configuration -The client merely needs to create a client-side proxy that will implement the agreed -upon interface ( `CheckingAccountService`). The resulting object created off the back of -the following bean definition can be injected into other client side objects, and the -proxy will take care of forwarding the call to the server-side object via JMS. +The client merely needs to create a client-side proxy that implements the agreed-upon +interface ( `CheckingAccountService`). +The following example defines beans that you can inject into other client-side objects (and the +proxy takes care of forwarding the call to the server-side object via JMS): + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -850,54 +913,56 @@ proxy will take care of forwarding the call to the server-side object via JMS. } ---- +==== [[remoting-amqp]] === AMQP -Refer to the {doc-spring-amqp}/html/_reference.html#remoting[Spring AMQP Reference Document +See the {doc-spring-amqp}/html/_reference.html#remoting[Spring AMQP Reference Guide's 'Spring Remoting with AMQP' section] for more information. - - [[remoting-autodection-remote-interfaces]] -=== Auto-detection is not implemented for remote interfaces +[NOTE] +==== +Auto-detection is not implemented for remote interfaces The main reason why auto-detection of implemented interfaces does not occur for remote interfaces is to avoid opening too many doors to remote callers. The target object might -implement internal callback interfaces like `InitializingBean` or `DisposableBean` which +implement internal callback interfaces, such as `InitializingBean` or `DisposableBean`, which one would not want to expose to callers. Offering a proxy with all interfaces implemented by the target usually does not matter -in the local case. But when exporting a remote service, you should expose a specific +in the local case. However, when you export a remote service, you should expose a specific service interface, with specific operations intended for remote usage. Besides internal -callback interfaces, the target might implement multiple business interfaces, with just -one of them intended for remote exposure. For these reasons, we __require__ such a +callback interfaces, the target might implement multiple business interfaces, with only +one of them intended for remote exposure. For these reasons, we require such a service interface to be specified. This is a trade-off between configuration convenience and the risk of accidental exposure of internal methods. Always specifying a service interface is not too much -effort, and puts you on the safe side regarding controlled exposure of specific methods. +effort and puts you on the safe side regarding controlled exposure of specific methods. +==== [[remoting-considerations]] -=== Considerations when choosing a technology +=== Considerations when Choosing a Technology -Each and every technology presented here has its drawbacks. You should carefully -consider your needs, the services you are exposing and the objects you'll be sending -over the wire when choosing a technology. +Each and every technology presented here has its drawbacks. When choosing a technology, you should carefully +consider your needs, the services you expose, and the objects you send +over the wire. -When using RMI, it's not possible to access the objects through the HTTP protocol, -unless you're tunneling the RMI traffic. RMI is a fairly heavy-weight protocol in that -it supports full-object serialization which is important when using a complex data model -that needs serialization over the wire. However, RMI-JRMP is tied to Java clients: It is +When using RMI, you cannot access the objects through the HTTP protocol, +unless you tunnel the RMI traffic. RMI is a fairly heavy-weight protocol, in that +it supports full-object serialization, which is important when you use a complex data model +that needs serialization over the wire. However, RMI-JRMP is tied to Java clients. It is a Java-to-Java remoting solution. Spring's HTTP invoker is a good choice if you need HTTP-based remoting but also rely on -Java serialization. It shares the basic infrastructure with RMI invokers, just using -HTTP as transport. Note that HTTP invokers are not only limited to Java-to-Java remoting -but also to Spring on both the client and server side. (The latter also applies to +Java serialization. It shares the basic infrastructure with RMI invokers but uses +HTTP as transport. Note that HTTP invokers are not limited only to Java-to-Java remoting +but also to Spring on both the client and the server side. (The latter also applies to Spring's RMI invoker for non-RMI interfaces.) Hessian might provide significant value when operating in a heterogeneous environment, @@ -906,17 +971,17 @@ limited. Known issues include the serialization of Hibernate objects in combinat lazily-initialized collections. If you have such a data model, consider using RMI or HTTP invokers instead of Hessian. -JMS can be useful for providing clusters of services and allowing the JMS broker to take -care of load balancing, discovery and auto-failover. By default: Java serialization is -used when using JMS remoting but the JMS provider could use a different mechanism for -the wire formatting, such as XStream to allow servers to be implemented in other +JMS can be useful for providing clusters of services and letting the JMS broker take +care of load balancing, discovery, and auto-failover. By default, Java serialization is +used for JMS remoting, but the JMS provider could use a different mechanism for +the wire formatting, such as XStream to let servers be implemented in other technologies. -Last but not least, EJB has an advantage over RMI in that it supports standard +Last but not least, EJB has an advantage over RMI, in that it supports standard role-based authentication and authorization and remote transaction propagation. It is possible to get RMI invokers or HTTP invokers to support security context propagation as -well, although this is not provided by core Spring: There are just appropriate hooks for -plugging in third-party or custom solutions here. +well, although this is not provided by core Spring. Spring offers only appropriate hooks for +plugging in third-party or custom solutions. @@ -925,22 +990,20 @@ plugging in third-party or custom solutions here. The Spring Framework provides two choices for making calls to REST endpoints: -* <> -- the original Spring REST client with a synchronous, template +* <>: The original Spring REST client with a synchronous, template method API. -* <> -- non-blocking, reactive alternative -that supports both sync and async, as well as streaming scenarios. +* <>: a non-blocking, reactive alternative +that supports both synchrnous and asynchronous as well as streaming scenarios. -[NOTE] -==== -As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the -`RestTemplate` with efficient support for both sync and async, as well as streaming +NOTE: As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the +`RestTemplate` with efficient support for both synchronous and asynchronous as well as streaming scenarios. The `RestTemplate` will be deprecated in a future version and will not have major new features added going forward. -==== + [[rest-resttemplate]] -==== RestTemplate +==== Using `RestTemplate` The `RestTemplate` provides a higher level API over HTTP client libraries. It makes it easy to invoke REST endpoints in a single line. It exposes the following groups of @@ -953,48 +1016,48 @@ overloaded methods: | Method group | Description | `getForObject` -| Retrieve a representation via GET. +| Retrieves a representation via GET. | `getForEntity` -| Retrieve a `ResponseEntity`, i.e. status, headers, and body, via GET. +| Retrieves a `ResponseEntity` (that is, status, headers, and body) by using GET. | `headForHeaders` -| Retrieve all headers for a resource via HEAD. +| Retrieves all headers for a resource by using HEAD. | `postForLocation` -| Create a new resource via POST and return the Location header from the response. +| Creates a new resource by using POST and returns the `Location` header from the response. | `postForObject` -| Create a new resource via POST and return the representation from the response. +| Creates a new resource by using POST and returns the representation from the response. | `postForEntity` -| Create a new resource via POST and return the representation from the response. +| Creates a new resource by using POST and returns the representation from the response. | `put` -| Create or update a resource via PUT. +| Creates or updates a resource by using PUT. | `patchForObject` -| Update a resource via PATCH and return the representation from the response. -Note that the JDK `HttpURLConnection` does not support the `PATCH` but Apache -HttpComponents, and others do. +| Updates a resource by using PATCH and returns the representation from the response. +Note that the JDK `HttpURLConnection` does not support the `PATCH`, but Apache +HttpComponents and others do. | `delete` -| Delete the resources at the specified URI via DELETE. +| Deletes the resources at the specified URI by using DELETE. | `optionsForAllow` -| Retrieve allowed HTTP methods for a resource via ALLOW. +| Retrieves allowed HTTP methods for a resource by using ALLOW. | `exchange` -| More generalized, and less opinionated version, of the above methods that provides extra -flexibility when needed. It accepts `RequestEntity`, including HTTP method, URL, headers, -and body as input, and returns a `ResponseEntity`. +| More generalized (and less opinionated) version of the preceding methods that provides extra +flexibility when needed. It accepts a `RequestEntity` (including HTTP method, URL, headers, +and body as input) and returns a `ResponseEntity`. These methods allow the use of `ParameterizedTypeReference` instead of `Class` to specify a response type with generics. | `execute` | The most generalized way to perform a request, with full control over request -preparation and response extraction via callback interfaces. +preparation and response extraction through callback interfaces. |=== @@ -1010,42 +1073,45 @@ There is built-in support for the following: * Netty * OkHttp -For example to switch to Apache HttpComponents use: +For example, to switch to Apache HttpComponents, you can use the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); ---- +==== Each `ClientHttpRequestFactory` exposes configuration options specific to the underlying -HTTP client library, e.g. for credentials, connection pooling, etc. +HTTP client library -- for example, for credentials, connection pooling, and other details. -[TIP] -==== -Note that the `java.net` implementation for HTTP requests may raise an exception when -accessing the status of a response that represents an error (e.g. 401). If this is an +TIP: Note that the `java.net` implementation for HTTP requests can raise an exception when +accessing the status of a response that represents an error (such as 401). If this is an issue, switch to another HTTP client library. -==== + [[rest-resttemplate-uri]] ===== URIs -Many of the `RestTemplate` methods accepts a URI template and URI template variables, -either as a `String` vararg, or as `Map`. +Many of the `RestTemplate` methods accept a URI template and URI template variables, +either as a `String` variable argumet, or as `Map`. -For example with a `String` vararg: +The following example uses a `String` variable argument: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- String result = restTemplate.getForObject( "http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21"); ---- +==== -Or with a `Map`: +The following example uses a `Map`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1054,9 +1120,11 @@ Or with a `Map`: String result = restTemplate.getForObject( "http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); ---- +==== -Keep in mind URI templates are automatically encoded. For example: +Keep in mind URI templates are automatically encoded, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1064,20 +1132,23 @@ Keep in mind URI templates are automatically encoded. For example: // Results in request to "http://example.com/hotel%20list" ---- +==== You can use the `uriTemplateHandler` property of `RestTemplate` to customize how URIs are -encoded. Or you can prepare a `java.net.URI` and pass it into one of the `RestTemplate` -methods that accept a `URI`. +encoded. Alternatively, you can prepare a `java.net.URI` and pass it into one of the `RestTemplate` +methods that accepts a `URI`. For more details on working with and encoding URIs, see <>. + [[rest-template-headers]] ===== Headers -Use the `exchange()` methods to specify request headers. For example: +You can use the `exchange()` methods to specify request headers, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1093,59 +1164,70 @@ Use the `exchange()` methods to specify request headers. For example: String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); String body = response.getBody(); ---- +==== -Response headers can be obtained through many `RestTemplate` method variants that return +You can obtain response headers through many `RestTemplate` method variants that return `ResponseEntity`. + [[rest-template-body]] ===== Body -Object passed into and returned from `RestTemplate` methods are converted to and from raw +Objects passed into and returned from `RestTemplate` methods are converted to and from raw content with the help of an `HttpMessageConverter`. -On a POST, an input object is serialized to the request body: +On a POST, an input object is serialized to the request body, as the following example shows: - URI location = template.postForLocation("http://example.com/people", person); +==== +---- +URI location = template.postForLocation("http://example.com/people", person); +---- +==== -The "Content-Type" header of the request does not need to be set explicitly. In most cases -a compatible message converter can be found based on the source Object type, and the chosen -message converter will set the content type accordingly. If necessary, you can use the -`exchange` methods to provide the "Content-Type" request header explicitly, and that in -turn will influence what message converter is selected. +You need not explicitly set the Content-Type header of the request. In most cases, +you can find a compatible message converter based on the source `Object` type, and the chosen +message converter sets the content type accordingly. If necessary, you can use the +`exchange` methods to explicitly provide the `Content-Type` request header, and that, in +turn, influences what message converter is selected. -On a GET, the body of the response is deserialized to an output Object: +On a GET, the body of the response is deserialized to an output `Object`, as the following example shows: - Person person = restTemplate.getForObject("http://example.com/people/{id}", Person.class, 42); +==== +---- +Person person = restTemplate.getForObject("http://example.com/people/{id}", Person.class, 42); +---- +==== -The "Accept" header of the request does not need to be set explicitly. In most cases +The `Accept` header of the request does not need to be explicitly set. In most cases, a compatible message converter can be found based on the expected response type, which -then helps to populate the "Accept" header. If necessary, you can use the `exchange` -methods to provide the "Accept" header explicitly. +then helps to populate the `Accept` header. If necessary, you can use the `exchange` +methods to provide the `Accept` header explicitly. -By default `RestTemplate` registers all built-in +By default, `RestTemplate` registers all built-in <>, depending on classpath checks that help to determine what optional conversion libraries are present. You can also set the message converters to use explicitly. + [[rest-message-conversion]] ===== Message Conversion -[.small]#<># +[.small]#<># The `spring-web` module contains the `HttpMessageConverter` contract for reading and -writing the body of HTTP requests and responses via `InputStream` and `OutputStream`. -``HttpMessageConverter``'s are used on the client side, e.g. in the `RestTemplate`, and -also on the server side, e.g. in Spring MVC REST controllers. +writing the body of HTTP requests and responses through `InputStream` and `OutputStream`. +`HttpMessageConverter` instances are used on the client side (for example, in the `RestTemplate`) and +on the server side (for example, in Spring MVC REST controllers). Concrete implementations for the main media (MIME) types are provided in the framework -and are registered by default with the `RestTemplate` on the client-side and with -`RequestMethodHandlerAdapter` on the server-side (see +and are, by default, registered with the `RestTemplate` on the client side and with +`RequestMethodHandlerAdapter` on the server side (see <>). -The implementations of ``HttpMessageConverter``s are described in the following sections. -For all converters a default media type is used but can be overridden by setting the -`supportedMediaTypes` bean property +The implementations of `HttpMessageConverter` are described in the following sections. +For all converters, a default media type is used, but you can override it by setting the +`supportedMediaTypes` bean property. The following table describes each implementation: [[rest-message-converters-tbl]] .HttpMessageConverter Implementations @@ -1154,51 +1236,51 @@ For all converters a default media type is used but can be overridden by setting | MessageConverter | Description | `StringHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write Strings from the HTTP -request and response. By default, this converter supports all text media types ( -`text/{asterisk}`), and writes with a `Content-Type` of `text/plain`. +| An `HttpMessageConverter` implementation that can read and write `String` instances from the HTTP +request and response. By default, this converter supports all text media types +(`text/{asterisk}`) and writes with a `Content-Type` of `text/plain`. | `FormHttpMessageConverter` | An `HttpMessageConverter` implementation that can read and write form data from the HTTP -request and response. By default, this converter reads and writes the media type -`application/x-www-form-urlencoded`. Form data is read from and written into a +request and response. By default, this converter reads and writes the +`application/x-www-form-urlencoded` media type. Form data is read from and written into a `MultiValueMap`. | `ByteArrayHttpMessageConverter` | An `HttpMessageConverter` implementation that can read and write byte arrays from the -HTTP request and response. By default, this converter supports all media types ( `{asterisk}/{asterisk}`), -and writes with a `Content-Type` of `application/octet-stream`. This can be overridden -by setting the `supportedMediaTypes` property, and overriding `getContentType(byte[])`. +HTTP request and response. By default, this converter supports all media types (`{asterisk}/{asterisk}`) +and writes with a `Content-Type` of `application/octet-stream`. You can override this +by setting the `supportedMediaTypes` property and overriding `getContentType(byte[])`. | `MarshallingHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write XML using Spring's +| An `HttpMessageConverter` implementation that can read and write XML by using Spring's `Marshaller` and `Unmarshaller` abstractions from the `org.springframework.oxm` package. -This converter requires a `Marshaller` and `Unmarshaller` before it can be used. These -can be injected via constructor or bean properties. By default this converter supports ( -`text/xml`) and ( `application/xml`). +This converter requires a `Marshaller` and `Unmarshaller` before it can be used. You can inject these +through constructor or bean properties. By default, this converter supports +`text/xml` and `application/xml`. | `MappingJackson2HttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write JSON using Jackson's -`ObjectMapper`. JSON mapping can be customized as needed through the use of Jackson's -provided annotations. When further control is needed, a custom `ObjectMapper` can be -injected through the `ObjectMapper` property for cases where custom JSON -serializers/deserializers need to be provided for specific types. By default this -converter supports ( `application/json`). +| An `HttpMessageConverter` implementation that can read and write JSON by using Jackson's +`ObjectMapper`. You can customize JSON mapping as needed through the use of Jackson's +provided annotations. When you need further control (for cases where custom JSON +serializers/deserializers need to be provided for specific types), you can inject a custom `ObjectMapper` +through the `ObjectMapper` property. By default, this +converter supports `application/json`. | `MappingJackson2XmlHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write XML using +| An `HttpMessageConverter` implementation that can read and write XML by using https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's -`XmlMapper`. XML mapping can be customized as needed through the use of JAXB -or Jackson's provided annotations. When further control is needed, a custom `XmlMapper` -can be injected through the `ObjectMapper` property for cases where custom XML -serializers/deserializers need to be provided for specific types. By default this -converter supports ( `application/xml`). +`XmlMapper`. You can customize XML mapping as needed through the use of JAXB +or Jackson's provided annotations. When you need further control (for cases where custom XML +serializers/deserializers need to be provided for specific types), you can inject a custom `XmlMapper` +through the `ObjectMapper` property. By default, this +converter supports `application/xml`. | `SourceHttpMessageConverter` | An `HttpMessageConverter` implementation that can read and write `javax.xml.transform.Source` from the HTTP request and response. Only `DOMSource`, -`SAXSource`, and `StreamSource` are supported. By default, this converter supports ( -`text/xml`) and ( `application/xml`). +`SAXSource`, and `StreamSource` are supported. By default, this converter supports +`text/xml` and `application/xml`. | `BufferedImageHttpMessageConverter` | An `HttpMessageConverter` implementation that can read and write @@ -1211,9 +1293,10 @@ and writes the media type supported by the Java I/O API. [[rest-template-jsonview]] ===== Jackson JSON Views -It is possible to specify a http://wiki.fasterxml.com/JacksonJsonViews[Jackson JSON View] -to serialize only a subset of the object properties. For example: +You can specify a http://wiki.fasterxml.com/JacksonJsonViews[Jackson JSON View] +to serialize only a subset of the object properties, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1225,15 +1308,19 @@ to serialize only a subset of the object properties. For example: ResponseEntity response = template.exchange(requestEntity, String.class); ---- +==== + + [[rest-template-multipart]] ===== Multipart To send multipart data, you need to provide a `MultiValueMap` whose values are -either Objects representing part content, or `HttpEntity` representing the content and +either `Object` instances that represent part content or `HttpEntity` instances that represent the content and headers for a part. `MultipartBodyBuilder` provides a convenient API to prepare a -multipart request: +multipart request, as the following example shows: +==== [source,java,intent=0] [subs="verbatim,quotes"] ---- @@ -1244,49 +1331,47 @@ multipart request: MultiValueMap> parts = builder.build(); ---- +==== -In most cases you do not have to specify the `Content-Type` for each part. The content -type is determined automatically based on the `HttpMessageConverter` chosen to serialize it, -or in the case of a `Resource` based on the file extension. If necessary you can -explicitly provide the `MediaType` to use for each part through one fo the overloaded +In most cases, you do not have to specify the `Content-Type` for each part. The content +type is determined automatically based on the `HttpMessageConverter` chosen to serialize it +or, in the case of a `Resource`, based on the file extension. If necessary, you can +explicitly provide the `MediaType` to use for each part through one of the overloaded builder `part` methods. -Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`: +Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as the following example shows: +==== [source,java,intent=0] [subs="verbatim,quotes"] ---- MultipartBodyBuilder builder = ...; template.postForObject("http://example.com/upload", builder.build(), Void.class); ---- +==== -If the `MultiValueMap` contains at least one non-String value, which could also be -represent regular form data (i.e. "application/x-www-form-urlencoded"), you don't have to -set the `Content-Type` to "multipart/form-data". This is always the case when using +If the `MultiValueMap` contains at least one non-`String` value, which could also be +represent regular form data (that is, `application/x-www-form-urlencoded`), you need not +set the `Content-Type` to `multipart/form-data`. This is always the case when you use `MultipartBodyBuilder` which ensures an `HttpEntity` wrapper. -[[rest-async-resttemplate]] -==== Async RestTemplate -The `AsyncRestTemplate` is deprecated. For all use cases where the `AsyncRestTemplate` -is considered for use, please use the <> instead. +[[rest-async-resttemplate]] +==== Using `AsyncRestTemplate` (Deprecated) +The `AsyncRestTemplate` is deprecated. For all use cases where you might consider using `AsyncRestTemplate`, +use the <> instead. [[ejb]] -== Enterprise JavaBeans (EJB) integration - - - -[[ejb-introduction]] -=== Introduction +== Enterprise JavaBeans (EJB) Integration As a lightweight container, Spring is often considered an EJB replacement. We do believe -that for many if not most applications and use cases, Spring as a container, combined +that for many, if not most, applications and use cases, Spring, as a container, combined with its rich supporting functionality in the area of transactions, ORM and JDBC access, -is a better choice than implementing equivalent functionality via an EJB container and +is a better choice than implementing equivalent functionality through an EJB container and EJBs. However, it is important to note that using Spring does not prevent you from using EJBs. @@ -1297,51 +1382,55 @@ remote EJB, or POJO (plain old Java object) variants, without the client code ha be changed. In this chapter, we look at how Spring can help you access and implement EJBs. Spring -provides particular value when accessing stateless session beans (SLSBs), so we'll begin -by discussing this. +provides particular value when accessing stateless session beans (SLSBs), so we begin +by discussing this topic. [[ejb-access]] === Accessing EJBs +This section covers how to access EJBs. + [[ejb-access-concepts]] ==== Concepts To invoke a method on a local or remote stateless session bean, client code must -normally perform a JNDI lookup to obtain the (local or remote) EJB Home object, then use -a 'create' method call on that object to obtain the actual (local or remote) EJB object. +normally perform a JNDI lookup to obtain the (local or remote) EJB Home object and then use +a `create` method call on that object to obtain the actual (local or remote) EJB object. One or more methods are then invoked on the EJB. To avoid repeated low-level code, many EJB applications use the Service Locator and Business Delegate patterns. These are better than spraying JNDI lookups throughout -client code, but their usual implementations have significant disadvantages. For example: +client code, but their usual implementations have significant disadvantages: -* Typically code using EJBs depends on Service Locator or Business Delegate singletons, +* Typically, code that uses EJBs depends on Service Locator or Business Delegate singletons, making it hard to test. * In the case of the Service Locator pattern used without a Business Delegate, - application code still ends up having to invoke the create() method on an EJB home, - and deal with the resulting exceptions. Thus it remains tied to the EJB API and the + application code still ends up having to invoke the `create()` method on an EJB home + and deal with the resulting exceptions. Thus, it remains tied to the EJB API and the complexity of the EJB programming model. * Implementing the Business Delegate pattern typically results in significant code - duplication, where we have to write numerous methods that simply call the same method + duplication, where we have to write numerous methods that call the same method on the EJB. -The Spring approach is to allow the creation and use of proxy objects, normally -configured inside a Spring container, which act as codeless business delegates. You do -not need to write another Service Locator, another JNDI lookup, or duplicate methods in -a hand-coded Business Delegate unless you are actually adding real value in such code. +The Spring approach is to allow the creation and use of proxy objects (normally +configured inside a Spring container), which act as codeless business delegates. You need +not write another Service Locator, another JNDI lookup, or duplicate methods in +a hand-coded Business Delegate unless you actually add real value in such code. + [[ejb-access-local]] -==== Accessing local SLSBs +==== Accessing Local SLSBs -Assume that we have a web controller that needs to use a local EJB. We'll follow best +Assume that we have a web controller that needs to use a local EJB. We follow best practice and use the EJB Business Methods Interface pattern, so that the EJB's local -interface extends a non EJB-specific business methods interface. Let's call this -business methods interface `MyComponent`. +interface extends a non-EJB-specific business methods interface. We call this +business methods interface `MyComponent`. The following example shows such an interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1349,18 +1438,20 @@ business methods interface `MyComponent`. ... } ---- +==== One of the main reasons to use the Business Methods Interface pattern is to ensure that synchronization between method signatures in local interface and bean implementation class is automatic. Another reason is that it later makes it much easier for us to switch to a POJO (plain old Java object) implementation of the service if it makes sense -to do so. Of course we'll also need to implement the local home interface and provide an +to do so. We also need to implement the local home interface and provide an implementation class that implements `SessionBean` and the `MyComponent` business -methods interface. Now the only Java coding we'll need to do to hook up our web tier +methods interface. Now, the only Java coding we need to do to hook up our web tier controller to the EJB implementation is to expose a setter method of type `MyComponent` -on the controller. This will save the reference as an instance variable in the -controller: +on the controller. This saves the reference as an instance variable in the +controller. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1370,13 +1461,15 @@ controller: this.myComponent = myComponent; } ---- +==== We can subsequently use this instance variable in any business method in the controller. -Now assuming we are obtaining our controller object out of a Spring container, we can +Now, assuming we obtain our controller object out of a Spring container, we can (in the same context) configure a `LocalStatelessSessionProxyFactoryBean` instance, -which will be the EJB proxy object. The configuration of the proxy, and setting of the -`myComponent` property of the controller is done with a configuration entry such as: +which is the EJB proxy object. We configure the proxy and set the +`myComponent` property of the controller with the following configuration entry: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1390,11 +1483,12 @@ which will be the EJB proxy object. The configuration of the proxy, and setting ---- +==== -There's a lot of work happening behind the scenes, courtesy of the Spring AOP framework, -although you aren't forced to work with AOP concepts to enjoy the results. The +A lot of work happens behind the scenes, courtesy of the Spring AOP framework, +although you are not forced to work with AOP concepts to enjoy the results. The `myComponent` bean definition creates a proxy for the EJB, which implements the business -method interface. The EJB local home is cached on startup, so there's only a single JNDI +method interface. The EJB local home is cached on startup, so there is only a single JNDI lookup. Each time the EJB is invoked, the proxy invokes the `classname` method on the local EJB and invokes the corresponding business method on the EJB. @@ -1402,8 +1496,10 @@ The `myController` bean definition sets the `myComponent` property of the contro class to the EJB proxy. Alternatively (and preferably in case of many such proxy definitions), consider using -the `` configuration element in Spring's "jee" namespace: +the `` configuration element in Spring's "`jee`" namespace. +The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -1414,130 +1510,127 @@ the `` configuration element in Spring's "jee" namespace: ---- +==== -This EJB access mechanism delivers huge simplification of application code: the web tier -code (or other EJB client code) has no dependence on the use of EJB. If we want to +This EJB access mechanism delivers huge simplification of application code. The web tier +code (or other EJB client code) has no dependence on the use of EJB. To replace this EJB reference with a POJO or a mock object or other test stub, we could -simply change the `myComponent` bean definition without changing a line of Java code. -Additionally, we haven't had to write a single line of JNDI lookup or other EJB plumbing +change the `myComponent` bean definition without changing a line of Java code. +Additionally, we have not had to write a single line of JNDI lookup or other EJB plumbing code as part of our application. Benchmarks and experience in real applications indicate that the performance overhead of -this approach (which involves reflective invocation of the target EJB) is minimal, and -is typically undetectable in typical use. Remember that we don't want to make -fine-grained calls to EJBs anyway, as there's a cost associated with the EJB +this approach (which involves reflective invocation of the target EJB) is minimal and +is undetectable in typical use. Remember that we do not want to make +fine-grained calls to EJBs anyway, as there is a cost associated with the EJB infrastructure in the application server. There is one caveat with regards to the JNDI lookup. In a bean container, this class is -normally best used as a singleton (there simply is no reason to make it a prototype). +normally best used as a singleton (there is no reason to make it a prototype). However, if that bean container pre-instantiates singletons (as do the various XML -`ApplicationContext` variants) you may have a problem if the bean container is loaded -before the EJB container loads the target EJB. That is because the JNDI lookup will be -performed in the `init()` method of this class and then cached, but the EJB will not -have been bound at the target location yet. The solution is to not pre-instantiate this -factory object, but allow it to be created on first use. In the XML containers, this is -controlled via the `lazy-init` attribute. - -Although this will not be of interest to the majority of Spring users, those doing +`ApplicationContext` variants), you can have a problem if the bean container is loaded +before the EJB container loads the target EJB. That is because the JNDI lookup is +performed in the `init()` method of this class and then cached, but the EJB has not +been bound at the target location yet. The solution is to not pre-instantiate this +factory object but to let it be created on first use. In the XML containers, you can control this +by using the `lazy-init` attribute. + +Although not of interest to the majority of Spring users, those doing programmatic AOP work with EJBs may want to look at `LocalSlsbInvokerInterceptor`. + [[ejb-access-remote]] -==== Accessing remote SLSBs +==== Accessing Remote SLSBs Accessing remote EJBs is essentially identical to accessing local EJBs, except that the `SimpleRemoteStatelessSessionProxyFactoryBean` or `` configuration -element is used. Of course, with or without Spring, remote invocation semantics apply; a +element is used. Of course, with or without Spring, remote invocation semantics apply: A call to a method on an object in another VM in another computer does sometimes have to be treated differently in terms of usage scenarios and failure handling. Spring's EJB client support adds one more advantage over the non-Spring approach. -Normally it is problematic for EJB client code to be easily switched back and forth +Normally, it is problematic for EJB client code to be easily switched back and forth between calling EJBs locally or remotely. This is because the remote interface methods must declare that they throw `RemoteException`, and client code must deal with this, -while the local interface methods don't. Client code written for local EJBs which needs +while the local interface methods need not. Client code written for local EJBs that needs to be moved to remote EJBs typically has to be modified to add handling for the remote -exceptions, and client code written for remote EJBs which needs to be moved to local -EJBs, can either stay the same but do a lot of unnecessary handling of remote -exceptions, or needs to be modified to remove that code. With the Spring remote EJB +exceptions, and client code written for remote EJBs that needs to be moved to local +EJBs can either stay the same but do a lot of unnecessary handling of remote +exceptions or be modified to remove that code. With the Spring remote EJB proxy, you can instead not declare any thrown `RemoteException` in your Business Method -Interface and implementing EJB code, have a remote interface which is identical except -that it does throw `RemoteException`, and rely on the proxy to dynamically treat the two +Interface and implementing EJB code, have a remote interface that is identical (except +that it does throw `RemoteException`), and rely on the proxy to dynamically treat the two interfaces as if they were the same. That is, client code does not have to deal with the checked `RemoteException` class. Any actual `RemoteException` that is thrown during the -EJB invocation will be re-thrown as the non-checked `RemoteAccessException` class, which -is a subclass of `RuntimeException`. The target service can then be switched at will +EJB invocation is re-thrown as the non-checked `RemoteAccessException` class, which +is a subclass of `RuntimeException`. You can then switch the target service at will between a local EJB or remote EJB (or even plain Java object) implementation, without -the client code knowing or caring. Of course, this is optional; there is nothing -stopping you from declaring `RemoteExceptions` in your business interface. +the client code knowing or caring. Of course, this is optional: Nothing +stops you from declaring `RemoteException` in your business interface. + [[ejb-access-ejb2-ejb3]] -==== Accessing EJB 2.x SLSBs versus EJB 3 SLSBs +==== Accessing EJB 2.x SLSBs Versus EJB 3 SLSBs -Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring is largely +Accessing EJB 2.x Session Beans and EJB 3 Session Beans through Spring is largely transparent. Spring's EJB accessors, including the `` and `` facilities, transparently adapt to the actual component at runtime. -They handle a home interface if found (EJB 2.x style), or perform straight component +They handle a home interface if found (EJB 2.x style) or perform straight component invocations if no home interface is available (EJB 3 style). -Note: For EJB 3 Session Beans, you could effectively use a `JndiObjectFactoryBean` / +Note: For EJB 3 Session Beans, you can effectively use a `JndiObjectFactoryBean` / `` as well, since fully usable component references are exposed for -plain JNDI lookups there. Defining explicit `` / `` -lookups simply provides consistent and more explicit EJB access configuration. - +plain JNDI lookups there. Defining explicit `` or `` +lookups provides consistent and more explicit EJB access configuration. [[jms]] == JMS (Java Message Service) - - -[[jms-introduction]] -=== Introduction - -Spring provides a JMS integration framework that simplifies the use of the JMS API much -like Spring's integration does for the JDBC API. +Spring provides a JMS integration framework that simplifies the use of the JMS API in much +the same way as Spring's integration does for the JDBC API. JMS can be roughly divided into two areas of functionality, namely the production and consumption of messages. The `JmsTemplate` class is used for message production and synchronous message reception. For asynchronous reception similar to Java EE's -message-driven bean style, Spring provides a number of message listener containers that -are used to create Message-Driven POJOs (MDPs). Spring also provides a declarative way -of creating message listeners. +message-driven bean style, Spring provides a number of message-listener containers that +you can use to create Message-Driven POJOs (MDPs). Spring also provides a declarative way +to create message listeners. -The package `org.springframework.jms.core` provides the core functionality for using +The `org.springframework.jms.core` package provides the core functionality for using JMS. It contains JMS template classes that simplify the use of the JMS by handling the creation and release of resources, much like the `JdbcTemplate` does for JDBC. The design principle common to Spring template classes is to provide helper methods to -perform common operations and for more sophisticated usage, delegate the essence of the -processing task to user implemented callback interfaces. The JMS template follows the -same design. The classes offer various convenience methods for the sending of messages, -consuming a message synchronously, and exposing the JMS session and message producer to +perform common operations and, for more sophisticated usage, delegate the essence of the +processing task to user-implemented callback interfaces. The JMS template follows the +same design. The classes offer various convenience methods for sending messages, +consuming messages synchronously, and exposing the JMS session and message producer to the user. -The package `org.springframework.jms.support` provides `JMSException` translation +The `org.springframework.jms.support` package provides `JMSException` translation functionality. The translation converts the checked `JMSException` hierarchy to a -mirrored hierarchy of unchecked exceptions. If there are any provider specific -subclasses of the checked `javax.jms.JMSException`, this exception is wrapped in the +mirrored hierarchy of unchecked exceptions. If any provider-specific +subclasses of the checked `javax.jms.JMSException` exist, this exception is wrapped in the unchecked `UncategorizedJmsException`. -The package `org.springframework.jms.support.converter` provides a `MessageConverter` +The `org.springframework.jms.support.converter` package provides a `MessageConverter` abstraction to convert between Java objects and JMS messages. -The package `org.springframework.jms.support.destination` provides various strategies +The `org.springframework.jms.support.destination` package provides various strategies for managing JMS destinations, such as providing a service locator for destinations stored in JNDI. -The package `org.springframework.jms.annotation` provides the necessary infrastructure -to support annotation-driven listener endpoints using `@JmsListener`. +The `org.springframework.jms.annotation` package provides the necessary infrastructure +to support annotation-driven listener endpoints by using `@JmsListener`. -The package `org.springframework.jms.config` provides the parser implementation for the -`jms` namespace as well the java config support to configure listener containers and +The `org.springframework.jms.config` package provides the parser implementation for the +`jms` namespace as well as the java config support to configure listener containers and create listener endpoints. -Finally, the package `org.springframework.jms.connection` provides an implementation of +Finally, the `org.springframework.jms.connection` package provides an implementation of the `ConnectionFactory` suitable for use in standalone applications. It also contains an implementation of Spring's `PlatformTransactionManager` for JMS (the cunningly named `JmsTransactionManager`). This allows for seamless integration of JMS as a transactional @@ -1548,53 +1641,51 @@ resource into Spring's transaction management mechanisms. [[jms-using]] === Using Spring JMS +This section describes how to use Spring's JMS components. [[jms-jmstemplate]] -==== JmsTemplate +==== Using `JmsTemplate` The `JmsTemplate` class is the central class in the JMS core package. It simplifies the -use of JMS since it handles the creation and release of resources when sending or +use of JMS, since it handles the creation and release of resources when sending or synchronously receiving messages. -Code that uses the `JmsTemplate` only needs to implement callback interfaces giving them -a clearly defined high level contract. The `MessageCreator` callback interface creates a -message given a `Session` provided by the calling code in `JmsTemplate`. In order to -allow for more complex usage of the JMS API, the callback `SessionCallback` provides the -user with the JMS session and the callback `ProducerCallback` exposes a `Session` and +Code that uses the `JmsTemplate` needs only to implement callback interfaces that give them +a clearly defined high-level contract. The `MessageCreator` callback interface creates a +message when given a `Session` provided by the calling code in `JmsTemplate`. To +allow for more complex usage of the JMS API, `SessionCallback` provides the +JMS session, and `ProducerCallback` exposes a `Session` and `MessageProducer` pair. The JMS API exposes two types of send methods, one that takes delivery mode, priority, and time-to-live as Quality of Service (QOS) parameters and one that takes no QOS -parameters which uses default values. Since there are many send methods in -`JmsTemplate`, the setting of the QOS parameters have been exposed as bean properties to +parameters and uses default values. Since `JmsTemplate` has many send methods, +setting the QOS parameters have been exposed as bean properties to avoid duplication in the number of send methods. Similarly, the timeout value for -synchronous receive calls is set using the property `setReceiveTimeout`. +synchronous receive calls is set by using the `setReceiveTimeout` property. Some JMS providers allow the setting of default QOS values administratively through the -configuration of the `ConnectionFactory`. This has the effect that a call to -``MessageProducer``'s send method `send(Destination destination, Message message)` will -use different QOS default values than those specified in the JMS specification. In order -to provide consistent management of QOS values, the `JmsTemplate` must therefore be +configuration of the `ConnectionFactory`. This has the effect that a call to a +`MessageProducer` instance's `send` method (`send(Destination destination, Message message)`) +uses different QOS default values than those specified in the JMS specification. In order +to provide consistent management of QOS values, the `JmsTemplate` must, therefore, be specifically enabled to use its own QOS values by setting the boolean property `isExplicitQosEnabled` to `true`. For convenience, `JmsTemplate` also exposes a basic request-reply operation that allows -to send a message and wait for a reply on a temporary queue that is created as part of +for sending a message and waiting for a reply on a temporary queue that is created as part of the operation. -[NOTE] -==== -Instances of the `JmsTemplate` class are __thread-safe once configured__. This is -important because it means that you can configure a single instance of a `JmsTemplate` -and then safely inject this __shared__ reference into multiple collaborators. To be +IMPORTANT: Instances of the `JmsTemplate` class are thread-safe, once configured. This is +important, because it means that you can configure a single instance of a `JmsTemplate` +and then safely inject this shared reference into multiple collaborators. To be clear, the `JmsTemplate` is stateful, in that it maintains a reference to a -`ConnectionFactory`, but this state is __not__ conversational state. -==== +`ConnectionFactory`, but this state is not conversational state. As of Spring Framework 4.1, `JmsMessagingTemplate` is built on top of `JmsTemplate` -and provides an integration with the messaging abstraction, i.e. -`org.springframework.messaging.Message`. This allows you to create the message to -send in generic manner. +and provides an integration with the messaging abstraction -- that is, +`org.springframework.messaging.Message`. This lets you create the message to +send in a generic manner. [[jms-connections]] @@ -1603,8 +1694,8 @@ send in generic manner. The `JmsTemplate` requires a reference to a `ConnectionFactory`. The `ConnectionFactory` is part of the JMS specification and serves as the entry point for working with JMS. It is used by the client application as a factory to create connections with the JMS -provider and encapsulates various configuration parameters, many of which are vendor -specific such as SSL configuration options. +provider and encapsulates various configuration parameters, many of which are +vendor-specific, such as SSL configuration options. When using JMS inside an EJB, the vendor provides implementations of the JMS interfaces so that they can participate in declarative transaction management and perform pooling @@ -1614,42 +1705,50 @@ the EJB or servlet deployment descriptors. To ensure the use of these features w `JmsTemplate` inside an EJB, the client application should ensure that it references the managed implementation of the `ConnectionFactory`. + + [[jms-caching-resources]] ===== Caching Messaging Resources -The standard API involves creating many intermediate objects. To send a message the -following 'API' walk is performed +The standard API involves creating many intermediate objects. To send a message, the +following 'API' walk is performed: +==== [literal] [subs="verbatim,quotes"] ---- ConnectionFactory->Connection->Session->MessageProducer->send ---- +==== + +Between the `ConnectionFactory` and the `Send` operation, three intermediate +objects are created and destroyed. To optimize the resource usage and increase +performance, Spring provides two implementations of `ConnectionFactory`. + -Between the ConnectionFactory and the Send operation there are three intermediate -objects that are created and destroyed. To optimise the resource usage and increase -performance two implementations of `ConnectionFactory` are provided. [[jms-connection-factory]] -===== SingleConnectionFactory +===== Using `SingleConnectionFactory` Spring provides an implementation of the `ConnectionFactory` interface, -`SingleConnectionFactory`, that will return the same `Connection` on all -`createConnection()` calls and ignore calls to `close()`. This is useful for testing and +`SingleConnectionFactory`, that returns the same `Connection` on all +`createConnection()` calls and ignores calls to `close()`. This is useful for testing and standalone environments so that the same connection can be used for multiple `JmsTemplate` calls that may span any number of transactions. `SingleConnectionFactory` takes a reference to a standard `ConnectionFactory` that would typically come from JNDI. + + [[jdbc-connection-factory-caching]] -===== CachingConnectionFactory +===== Using `CachingConnectionFactory` The `CachingConnectionFactory` extends the functionality of `SingleConnectionFactory` -and adds the caching of Sessions, MessageProducers, and MessageConsumers. The initial -cache size is set to 1, use the property `sessionCacheSize` to increase the number of -cached sessions. Note that the number of actual cached sessions will be more than that -number as sessions are cached based on their acknowledgment mode, so there can be up to -4 cached session instances when `sessionCacheSize` is set to one, one for each -acknowledgment mode. MessageProducers and MessageConsumers are cached within their +and adds the caching of `Session`, `MessageProducer`, and `MessageConsumer` instances. The initial +cache size is set to `1`. You can use the `sessionCacheSize` property to increase the number of +cached sessions. Note that the number of actual cached sessions is more than that +number, as sessions are cached based on their acknowledgment mode, so there can be up to +four cached session instances (one for each +acknowledgment mode) when `sessionCacheSize` is set to one . `MessageProducer` and `MessageConsumer` instances are cached within their owning session and also take into account the unique properties of the producers and consumers when caching. MessageProducers are cached based on their destination. MessageConsumers are cached based on a key composed of the destination, selector, @@ -1659,178 +1758,180 @@ noLocal delivery flag, and the durable subscription name (if creating durable co [[jms-destinations]] ==== Destination Management -Destinations, like ConnectionFactories, are JMS administered objects that can be stored -and retrieved in JNDI. When configuring a Spring application context you can use the -JNDI factory class `JndiObjectFactoryBean` / `` to perform dependency -injection on your object's references to JMS destinations. However, often this strategy -is cumbersome if there are a large number of destinations in the application or if there +Destinations, as `ConnectionFactory` instances, are JMS administered objects that you can store +and retrieved in JNDI. When configuring a Spring application context, you can use the +JNDI `JndiObjectFactoryBean` factory class or `` to perform dependency +injection on your object's references to JMS destinations. However, this strategy +is often cumbersome if there are a large number of destinations in the application or if there are advanced destination management features unique to the JMS provider. Examples of -such advanced destination management would be the creation of dynamic destinations or +such advanced destination management include the creation of dynamic destinations or support for a hierarchical namespace of destinations. The `JmsTemplate` delegates the -resolution of a destination name to a JMS destination object to an implementation of the -interface `DestinationResolver`. `DynamicDestinationResolver` is the default +resolution of a destination name to a JMS destination object that implements the +`DestinationResolver` interface. `DynamicDestinationResolver` is the default implementation used by `JmsTemplate` and accommodates resolving dynamic destinations. A -`JndiDestinationResolver` is also provided that acts as a service locator for +`JndiDestinationResolver` is also provided to act as a service locator for destinations contained in JNDI and optionally falls back to the behavior contained in `DynamicDestinationResolver`. -Quite often the destinations used in a JMS application are only known at runtime and -therefore cannot be administratively created when the application is deployed. This is +Quite often, the destinations used in a JMS application are only known at runtime and, +therefore, cannot be administratively created when the application is deployed. This is often because there is shared application logic between interacting system components that create destinations at runtime according to a well-known naming convention. Even though the creation of dynamic destinations is not part of the JMS specification, most -vendors have provided this functionality. Dynamic destinations are created with a name -defined by the user which differentiates them from temporary destinations and are often +vendors have provided this functionality. Dynamic destinations are created with a user-defined name, +which differentiates them from temporary destinations, and are often not registered in JNDI. The API used to create dynamic destinations varies from provider -to provider since the properties associated with the destination are vendor specific. +to provider since the properties associated with the destination are vendor-specific. However, a simple implementation choice that is sometimes made by vendors is to -disregard the warnings in the JMS specification and to use the `TopicSession` method -`createTopic(String topicName)` or the `QueueSession` method `createQueue(String -queueName)` to create a new destination with default destination properties. Depending -on the vendor implementation, `DynamicDestinationResolver` may then also create a +disregard the warnings in the JMS specification and to use the method `TopicSession` +`createTopic(String topicName)` or the `QueueSession` `createQueue(String +queueName)` method to create a new destination with default destination properties. Depending +on the vendor implementation, `DynamicDestinationResolver` can then also create a physical destination instead of only resolving one. The boolean property `pubSubDomain` is used to configure the `JmsTemplate` with -knowledge of what JMS domain is being used. By default the value of this property is -false, indicating that the point-to-point domain, Queues, will be used. This property -used by `JmsTemplate` determines the behavior of dynamic destination resolution via +knowledge of what JMS domain is being used. By default, the value of this property is +false, indicating that the point-to-point domain, `Queues`, is to be used. This property +(used by `JmsTemplate`) determines the behavior of dynamic destination resolution through implementations of the `DestinationResolver` interface. -You can also configure the `JmsTemplate` with a default destination via the property -`defaultDestination`. The default destination will be used with send and receive +You can also configure the `JmsTemplate` with a default destination through the +property `defaultDestination`. The default destination is with send and receive operations that do not refer to a specific destination. + [[jms-mdp]] ==== Message Listener Containers One of the most common uses of JMS messages in the EJB world is to drive message-driven beans (MDBs). Spring offers a solution to create message-driven POJOs (MDPs) in a way that does not tie a user to an EJB container. (See <> -for detailed coverage of Spring's MDP support.) As from Spring Framework 4.1, endpoint -methods can be simply annotated using `@JmsListener` see <> for more +for detailed coverage of Spring's MDP support.) Since Spring Framework 4.1, endpoint +methods can be annotated with `@JmsListener` -- see <> for more details. A message listener container is used to receive messages from a JMS message queue and drive the `MessageListener` that is injected into it. The listener container is responsible for all threading of message reception and dispatches into the listener for processing. A message listener container is the intermediary between an MDP and a -messaging provider, and takes care of registering to receive messages, participating in -transactions, resource acquisition and release, exception conversion and suchlike. This -allows you as an application developer to write the (possibly complex) business logic -associated with receiving a message (and possibly responding to it), and delegates +messaging provider and takes care of registering to receive messages, participating in +transactions, resource acquisition and release, exception conversion, and so on. This +lets you write the (possibly complex) business logic +associated with receiving a message (and possibly respond to it), and delegates boilerplate JMS infrastructure concerns to the framework. There are two standard JMS message listener containers packaged with Spring, each with -its specialised feature set. +its specialized feature set. + +* <> +* <> [[jms-mdp-simple]] -===== SimpleMessageListenerContainer +===== Using `SimpleMessageListenerContainer` This message listener container is the simpler of the two standard flavors. It creates a -fixed number of JMS sessions and consumers at startup, registers the listener using the +fixed number of JMS sessions and consumers at startup, registers the listener by using the standard JMS `MessageConsumer.setMessageListener()` method, and leaves it up the JMS provider to perform listener callbacks. This variant does not allow for dynamic adaption to runtime demands or for participation in externally managed transactions. Compatibility-wise, it stays very close to the spirit of the standalone JMS -specification - but is generally not compatible with Java EE's JMS restrictions. +specification, but is generally not compatible with Java EE's JMS restrictions. -[NOTE] -==== -While `SimpleMessageListenerContainer` does not allow for the participation in externally -managed transactions, it does support native JMS transactions: simply switch the -'sessionTransacted' flag to 'true' or, in the namespace, set the 'acknowledge' attribute -to 'transacted': Exceptions thrown from your listener will lead to a rollback then, with -the message getting redelivered. Alternatively, consider using 'CLIENT_ACKNOWLEDGE' mode +NOTE: While `SimpleMessageListenerContainer` does not allow for participation in externally +managed transactions, it does support native JMS transactions. To enable this feature, you can switch the +`sessionTransacted` flag to `true` or, in the XML namespace, set the `acknowledge` attribute +to `transacted`. Exceptions thrown from your listener then lead to a rollback, with +the message getting redelivered. Alternatively, consider using `CLIENT_ACKNOWLEDGE` mode, which provides redelivery in case of an exception as well but does not use transacted -Sessions and therefore does not include any other Session operations (such as sending +`Session` instances and, therefore, does not include any other `Session` operations (such as sending response messages) in the transaction protocol. -**The default 'AUTO_ACKNOWLEDGE' mode does not provide proper reliability guarantees.** -Messages may get lost when listener execution fails (since the provider will automatically -acknowledge each message after listener invocation, with no exceptions to be propagated to -the provider) or when the listener container shuts down (this may be configured through -the 'acceptMessagesWhileStopping' flag). Make sure to use transacted sessions in case of -reliability needs, e.g. for reliable queue handling and durable topic subscriptions. -==== +IMPORTANT: The default `AUTO_ACKNOWLEDGE` mode does not provide proper reliability guarantees. +Messages can get lost when listener execution fails (since the provider automatically +acknowledges each message after listener invocation, with no exceptions to be propagated to +the provider) or when the listener container shuts down (you can configure this by setting +the `acceptMessagesWhileStopping` flag). Make sure to use transacted sessions in case of +reliability needs (for example, for reliable queue handling and durable topic subscriptions). + + [[jms-mdp-default]] -===== DefaultMessageListenerContainer +===== Using `DefaultMessageListenerContainer` -This message listener container is the one used in most cases. In contrast to +This message listener container is used in most cases. In contrast to `SimpleMessageListenerContainer`, this container variant allows for dynamic adaptation to runtime demands and is able to participate in externally managed transactions. Each received message is registered with an XA transaction when configured with a -`JtaTransactionManager`; so processing may take advantage of XA transaction semantics. +`JtaTransactionManager`. As a result, processing may take advantage of XA transaction semantics. This listener container strikes a good balance between low requirements on the JMS -provider, advanced functionality such as the participation in externally managed -transactions, and compatibility with Java EE environments. +provider, advanced functionality (such as participation in externally managed +transactions), and compatibility with Java EE environments. -The cache level of the container can be customized. Note that when no caching is enabled, +You can customize the cache level of the container. Note that, when no caching is enabled, a new connection and a new session is created for each message reception. Combining this -with a non durable subscription with high loads may lead to message lost. Make sure to -use a proper cache level in such case. +with a non-durable subscription with high loads may lead to message loss. Make sure to +use a proper cache level in such a case. This container also has recoverable capabilities when the broker goes down. By default, -a simple `BackOff` implementation retries every 5 seconds. It is possible to specify -a custom `BackOff` implementation for more fine-grained recovery options, see -`ExponentialBackOff` for an example. - -[NOTE] -==== -Like its sibling `SimpleMessageListenerContainer`, `DefaultMessageListenerContainer` -supports native JMS transactions and also allows for customizing the acknowledgment mode. -This is strongly recommended over externally managed transactions if feasible for your -scenario: that is, if you can live with occasional duplicate messages in case of the -JVM dying. Custom duplicate message detection steps in your business logic may cover -such situations, e.g. in the form of a business entity existence check or a protocol -table check. Any such arrangements will be significantly more efficient than the +a simple `BackOff` implementation retries every five seconds. You can specify +a custom `BackOff` implementation for more fine-grained recovery options. See +api-spring-framework/util/backoff/ExponentialBackOff.html[`ExponentialBackOff`] for an example. + +NOTE: Like its sibling (<>), `DefaultMessageListenerContainer` +supports native JMS transactions and allows for customizing the acknowledgment mode. +If feasible for your +scenario, This is strongly recommended over externally managed transactions -- that is, if you can live with occasional duplicate messages in case of the +JVM dying. Custom duplicate message detection steps in your business logic can cover +such situations -- for example, in the form of a business entity existence check or a protocol +table check. Any such arrangements are significantly more efficient than the alternative: wrapping your entire processing with an XA transaction (through configuring -your `DefaultMessageListenerContainer` with an `JtaTransactionManager`), covering the +your `DefaultMessageListenerContainer` with an `JtaTransactionManager`) to cover the reception of the JMS message as well as the execution of the business logic in your message listener (including database operations etc). -**The default 'AUTO_ACKNOWLEDGE' mode does not provide proper reliability guarantees.** -Messages may get lost when listener execution fails (since the provider will automatically -acknowledge each message before listener invocation) or when the listener container shuts -down (this may be configured through the 'acceptMessagesWhileStopping' flag). Make sure -to use transacted sessions in case of reliability needs, e.g. for reliable queue handling -and durable topic subscriptions. -==== + +IMPORTANT: The default `AUTO_ACKNOWLEDGE` mode does not provide proper reliability guarantees. +Messages can get lost when listener execution fails (since the provider automatically +acknowledges each message after listener invocation, with no exceptions to be propagated to +the provider) or when the listener container shuts down (you can configure this by setting +the `acceptMessagesWhileStopping` flag). Make sure to use transacted sessions in case of +reliability needs (for example, for reliable queue handling and durable topic subscriptions). + [[jms-tx]] -==== Transaction management +==== Transaction Management Spring provides a `JmsTransactionManager` that manages transactions for a single JMS -`ConnectionFactory`. This allows JMS applications to leverage the managed transaction -features of Spring as described in <>. +`ConnectionFactory`. This lets JMS applications leverage the managed-transaction +features of Spring, as described in <>. The `JmsTransactionManager` performs local resource transactions, binding a JMS Connection/Session pair from the specified `ConnectionFactory` to the thread. `JmsTemplate` automatically detects such transactional resources and operates on them accordingly. -In a Java EE environment, the `ConnectionFactory` will pool Connections and Sessions, so +In a Java EE environment, the `ConnectionFactory` pools Connection and Session instances, so those resources are efficiently reused across transactions. In a standalone environment, -using Spring's `SingleConnectionFactory` will result in a shared JMS `Connection`, with +using Spring's `SingleConnectionFactory` result in a shared JMS `Connection`, with each transaction having its own independent `Session`. Alternatively, consider the use -of a provider-specific pooling adapter such as ActiveMQ's `PooledConnectionFactory` +of a provider-specific pooling adapter, such as ActiveMQ's `PooledConnectionFactory` class. -`JmsTemplate` can also be used with the `JtaTransactionManager` and an XA-capable JMS -`ConnectionFactory` for performing distributed transactions. Note that this requires the -use of a JTA transaction manager as well as a properly XA-configured ConnectionFactory! -(Check your Java EE server's / JMS provider's documentation.) +You can also use `JmsTemplate` with the `JtaTransactionManager` and an XA-capable JMS +`ConnectionFactory` to perform distributed transactions. Note that this requires the +use of a JTA transaction manager as well as a properly XA-configured ConnectionFactory. +(Check your Java EE server's or JMS provider's documentation.) Reusing code across a managed and unmanaged transactional environment can be confusing when using the JMS API to create a `Session` from a `Connection`. This is because the -JMS API has only one factory method to create a `Session` and it requires values for the +JMS API has only one factory method to create a `Session`, and it requires values for the transaction and acknowledgment modes. In a managed environment, setting these values is the responsibility of the environment's transactional infrastructure, so these values -are ignored by the vendor's wrapper to the JMS Connection. When using the `JmsTemplate` -in an unmanaged environment you can specify these values through the use of the -properties `sessionTransacted` and `sessionAcknowledgeMode`. When using a -`PlatformTransactionManager` with `JmsTemplate`, the template will always be given a +are ignored by the vendor's wrapper to the JMS Connection. When you use the `JmsTemplate` +in an unmanaged environment, you can specify these values through the use of the +properties `sessionTransacted` and `sessionAcknowledgeMode`. When you use a +`PlatformTransactionManager` with `JmsTemplate`, the template is always given a transactional JMS `Session`. @@ -1838,11 +1939,15 @@ transactional JMS `Session`. [[jms-sending]] === Sending a Message -The `JmsTemplate` contains many convenience methods to send a message. There are send -methods that specify the destination using a `javax.jms.Destination` object and those -that specify the destination using a string for use in a JNDI lookup. The send method +The `JmsTemplate` contains many convenience methods to send a message. Send +methods specify the destination by using a `javax.jms.Destination` object, and others +specify the destination by using a `String` in a JNDI lookup. The `send` method that takes no destination argument uses the default destination. +The following example uses the `MessageCreator` callback to create a text message from the +supplied `Session` object: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1877,17 +1982,17 @@ that takes no destination argument uses the default destination. } } ---- +==== -This example uses the `MessageCreator` callback to create a text message from the -supplied `Session` object. The `JmsTemplate` is constructed by passing a reference to a -`ConnectionFactory`. As an alternative, a zero argument constructor and +In the preceding example, the `JmsTemplate` is constructed by passing a reference to a +`ConnectionFactory`. As an alternative, a zero-argument constructor and `connectionFactory` is provided and can be used for constructing the instance in -JavaBean style (using a BeanFactory or plain Java code). Alternatively, consider +JavaBean style (using a `BeanFactory` or plain Java code). Alternatively, consider deriving from Spring's `JmsGatewaySupport` convenience base class, which provides pre-built bean properties for JMS configuration. -The method `send(String destinationName, MessageCreator creator)` lets you send a -message using the string name of the destination. If these names are registered in JNDI, +The `send(String destinationName, MessageCreator creator)` method lets you send a +message by using the string name of the destination. If these names are registered in JNDI, you should set the `destinationResolver` property of the template to an instance of `JndiDestinationResolver`. @@ -1895,31 +2000,33 @@ If you created the `JmsTemplate` and specified a default destination, the `send(MessageCreator c)` sends a message to that destination. + [[jms-msg-conversion]] ==== Using Message Converters -In order to facilitate the sending of domain model objects, the `JmsTemplate` has +To facilitate the sending of domain model objects, the `JmsTemplate` has various send methods that take a Java object as an argument for a message's data -content. The overloaded methods `convertAndSend()` and `receiveAndConvert()` in +content. The overloaded methods `convertAndSend()` and `receiveAndConvert()` methods in `JmsTemplate` delegate the conversion process to an instance of the `MessageConverter` interface. This interface defines a simple contract to convert between Java objects and -JMS messages. The default implementation `SimpleMessageConverter` supports conversion +JMS messages. The default implementation (`SimpleMessageConverter`) supports conversion between `String` and `TextMessage`, `byte[]` and `BytesMesssage`, and `java.util.Map` and `MapMessage`. By using the converter, you and your application code can focus on the -business object that is being sent or received via JMS and not be concerned with the +business object that is being sent or received through JMS and not be concerned with the details of how it is represented as a JMS message. -The sandbox currently includes a `MapMessageConverter` which uses reflection to convert +The sandbox currently includes a `MapMessageConverter`, which uses reflection to convert between a JavaBean and a `MapMessage`. Other popular implementation choices you might -implement yourself are Converters that use an existing XML marshalling package, such as -JAXB, Castor or XStream, to create a `TextMessage` representing the object. +implement yourself are converters that use an existing XML marshalling package (such as +JAXB, Castor, or XStream) to create a `TextMessage` that represents the object. To accommodate the setting of a message's properties, headers, and body that can not be generically encapsulated inside a converter class, the `MessagePostProcessor` interface -gives you access to the message after it has been converted, but before it is sent. The -example below demonstrates how to modify a message header and a property after a -`java.util.Map` is converted to a message. +gives you access to the message after it has been converted but before it is sent. The +following example shows how to modify a message header and a property after a +`java.util.Map` is converted to a message: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -1936,9 +2043,11 @@ example below demonstrates how to modify a message header and a property after a }); } ---- +==== -This results in a message of the form: +This results in a message of the following form: +==== [literal] [subs="verbatim,quotes"] ---- @@ -1956,54 +2065,57 @@ MapMessage={ } } ---- +==== + [[jms-callbacks]] -==== SessionCallback and ProducerCallback +==== Using `SessionCallback` and `ProducerCallback` -While the send operations cover many common usage scenarios, there are cases when you +While the send operations cover many common usage scenarios, you might sometimes want to perform multiple operations on a JMS `Session` or `MessageProducer`. The `SessionCallback` and `ProducerCallback` expose the JMS `Session` and `Session` / -`MessageProducer` pair respectively. The `execute()` methods on `JmsTemplate` execute +`MessageProducer` pair, respectively. The `execute()` methods on `JmsTemplate` execute these callback methods. [[jms-receiving]] -=== Receiving a message +=== Receiving a Message + +This describes how to recieve messages with JMS in Spring. [[jms-receiving-sync]] -==== Synchronous reception +==== Synchronous Reception -While JMS is typically associated with asynchronous processing, it is possible to +While JMS is typically associated with asynchronous processing, you can consume messages synchronously. The overloaded `receive(..)` methods provide this functionality. During a synchronous receive, the calling thread blocks until a message -becomes available. This can be a dangerous operation since the calling thread can -potentially be blocked indefinitely. The property `receiveTimeout` specifies how long +becomes available. This can be a dangerous operation, since the calling thread can +potentially be blocked indefinitely. The `receiveTimeout` property specifies how long the receiver should wait before giving up waiting for a message. + [[jms-asynchronousMessageReception]] ==== Asynchronous reception: Message-Driven POJOs -[NOTE] -==== -Spring also supports annotated-listener endpoints through the use of the `@JmsListener` +NOTE: Spring also supports annotated-listener endpoints through the use of the `@JmsListener` annotation and provides an open infrastructure to register endpoints programmatically. This -is by far the most convenient way to setup an asynchronous receiver, see +is, by far, the most convenient way to setup an asynchronous receiver. See <> for more details. -==== In a fashion similar to a Message-Driven Bean (MDB) in the EJB world, the Message-Driven -POJO (MDP) acts as a receiver for JMS messages. The one restriction (but see also below -for the discussion of the `MessageListenerAdapter` class) on an MDP is that it must -implement the `javax.jms.MessageListener` interface. Please also be aware that in the -case where your POJO will be receiving messages on multiple threads, it is important to +POJO (MDP) acts as a receiver for JMS messages. The one restriction (but see +<>) on an MDP is that it must +implement the `javax.jms.MessageListener` interface. Note that, if +your POJO receives messages on multiple threads, it is important to ensure that your implementation is thread-safe. -Below is a simple implementation of an MDP: +The following example shows a simple implementation of an MDP: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2029,13 +2141,15 @@ Below is a simple implementation of an MDP: } } ---- +==== -Once you've implemented your `MessageListener`, it's time to create a message listener +Once you have implemented your `MessageListener`, it is time to create a message listener container. -Find below an example of how to define and configure one of the message listener -containers that ships with Spring (in this case the `DefaultMessageListenerContainer`). +The following example shows how to define and configure one of the message listener +containers that ships with Spring (in this case, `DefaultMessageListenerContainer`): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2049,18 +2163,22 @@ containers that ships with Spring (in this case the `DefaultMessageListenerConta **** ---- +==== -Please refer to the Spring javadocs of the various message listener containers for a full +See the Spring Javadoc of the various message listener containers (all of which implement {api-spring-framework}/jms/listener/MessageListenerContainer.html[MessageListenerContainer]) for a full description of the features supported by each implementation. + [[jms-receiving-async-session-aware-message-listener]] -==== SessionAwareMessageListener interface +==== Using the `SessionAwareMessageListener` Interface The `SessionAwareMessageListener` interface is a Spring-specific interface that provides -a similar contract to the JMS `MessageListener` interface, but also provides the message -handling method with access to the JMS `Session` from which the `Message` was received. +a similar contract to the JMS `MessageListener` interface but also gives the message-handling +method access to the JMS `Session` from which the `Message` was received. +The following listing shows the definition of the `SessionAwareMessageListener` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2071,10 +2189,11 @@ handling method with access to the JMS `Session` from which the `Message` was re void onMessage(Message message, Session session) throws JMSException; } ---- +==== You can choose to have your MDPs implement this interface (in preference to the standard JMS `MessageListener` interface) if you want your MDPs to be able to respond to any -received messages (using the `Session` supplied in the `onMessage(Message, Session)` +received messages (by using the `Session` supplied in the `onMessage(Message, Session)` method). All of the message listener container implementations that ship with Spring have support for MDPs that implement either the `MessageListener` or `SessionAwareMessageListener` interface. Classes that implement the @@ -2082,25 +2201,23 @@ have support for MDPs that implement either the `MessageListener` or through the interface. The choice of whether or not to use it is left entirely up to you as an application developer or architect. -Please note that the `'onMessage(..)'` method of the `SessionAwareMessageListener` +Note that the `onMessage(..)` method of the `SessionAwareMessageListener` interface throws `JMSException`. In contrast to the standard JMS `MessageListener` interface, when using the `SessionAwareMessageListener` interface, it is the -responsibility of the client code to handle any exceptions thrown. +responsibility of the client code to handle any thrown exceptions. + [[jms-receiving-async-message-listener-adapter]] -==== MessageListenerAdapter +==== Using `MessageListenerAdapter` The `MessageListenerAdapter` class is the final component in Spring's asynchronous -messaging support: in a nutshell, it allows you to expose almost __any__ class as a MDP -(there are of course some constraints). +messaging support. In a nutshell, it lets you expose almost any class as an MDP +(though there are some constraints). -Consider the following interface definition. Notice that although the interface extends -neither the `MessageListener` nor `SessionAwareMessageListener` interfaces, it can still -be used as a MDP via the use of the `MessageListenerAdapter` class. Notice also how the -various message handling methods are strongly typed according to the __contents__ of the -various `Message` types that they can receive and handle. +Consider the following interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2115,7 +2232,17 @@ various `Message` types that they can receive and handle. void handleMessage(Serializable message); } ---- +==== +Notice that, although the interface extends +neither the `MessageListener` nor the `SessionAwareMessageListener` interface, you can still use it +as a MDP by using the `MessageListenerAdapter` class. Notice also how the +various message handling methods are strongly typed according to the contents of the +various `Message` types that they can receive and handle. + +Now consider the following implementation of the `MessageDelegate` interface: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2123,11 +2250,13 @@ various `Message` types that they can receive and handle. // implementation elided for clarity... } ---- +==== -In particular, note how the above implementation of the `MessageDelegate` interface (the -above `DefaultMessageDelegate` class) has __no__ JMS dependencies at all. It truly is a -POJO that we will make into an MDP via the following configuration. +In particular, note how the preceding implementation of the `MessageDelegate` interface (the +`DefaultMessageDelegate` class) has no JMS dependencies at all. It truly is a +POJO that we can make into an MDP through the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2145,14 +2274,17 @@ POJO that we will make into an MDP via the following configuration. **** ---- +==== -Below is an example of another MDP that can only handle the receiving of JMS +The next example shows another MDP that can handle only receiving JMS `TextMessage` messages. Notice how the message handling method is actually called -`'receive'` (the name of the message handling method in a `MessageListenerAdapter` -defaults to `'handleMessage'`), but it is configurable (as you will see below). Notice -also how the `'receive(..)'` method is strongly typed to receive and respond only to JMS +`receive` (the name of the message handling method in a `MessageListenerAdapter` +defaults to `handleMessage`), but it is configurable (as you can see later in this section). Notice +also how the `receive(..)` method is strongly typed to receive and respond only to JMS `TextMessage` messages. +The following listing shows the definition of the `TextMessageDelegage` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2161,7 +2293,11 @@ also how the `'receive(..)'` method is strongly typed to receive and respond onl void receive(TextMessage message); } ---- +==== + +The following listing shows a class that implements the `TextMessageDelegate` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2169,9 +2305,11 @@ also how the `'receive(..)'` method is strongly typed to receive and respond onl // implementation elided for clarity... } ---- +==== -The configuration of the attendant `MessageListenerAdapter` would look like this: +The configuration of the attendant `MessageListenerAdapter` would then be as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2186,13 +2324,15 @@ The configuration of the attendant `MessageListenerAdapter` would look like this ---- +==== -Please note that if the above `'messageListener'` receives a JMS `Message` of a type -other than `TextMessage`, an `IllegalStateException` will be thrown (and subsequently +Note that, if the `messageListener` receives a JMS `Message` of a type +other than `TextMessage`, an `IllegalStateException` is thrown (and subsequently swallowed). Another of the capabilities of the `MessageListenerAdapter` class is the ability to automatically send back a response `Message` if a handler method returns a -non-void value. Consider the interface and class: +non-void value. Consider the following interface and class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2210,33 +2350,38 @@ non-void value. Consider the interface and class: // implementation elided for clarity... } ---- +==== -If the above `DefaultResponsiveTextMessageDelegate` is used in conjunction with a -`MessageListenerAdapter` then any non-null value that is returned from the execution of -the `'receive(..)'` method will (in the default configuration) be converted into a -`TextMessage`. The resulting `TextMessage` will then be sent to the `Destination` (if -one exists) defined in the JMS Reply-To property of the original `Message`, or the -default `Destination` set on the `MessageListenerAdapter` (if one has been configured); -if no `Destination` is found then an `InvalidDestinationException` will be thrown (and -please note that this exception __will not__ be swallowed and __will__ propagate up the +If you use the `DefaultResponsiveTextMessageDelegate` in conjunction with a +`MessageListenerAdapter`, any non-null value that is returned from the execution of +the `'receive(..)'` method is (in the default configuration) converted into a +`TextMessage`. The resulting `TextMessage` is then sent to the `Destination` (if +one exists) defined in the JMS `Reply-To` property of the original `Message` or the +default `Destination` set on the `MessageListenerAdapter` (if one has been configured). +If no `Destination` is found, an `InvalidDestinationException` is thrown +(note that this exception is not swallowed and propagates up the call stack). + [[jms-tx-participation]] -==== Processing messages within transactions +==== Processing Messages Within Transactions -Invoking a message listener within a transaction only requires reconfiguration of the +Invoking a message listener within a transaction requires only reconfiguration of the listener container. -Local resource transactions can simply be activated through the `sessionTransacted` flag -on the listener container definition. Each message listener invocation will then operate +You can activate local resource transactions through the `sessionTransacted` flag +on the listener container definition. Each message listener invocation then operates within an active JMS transaction, with message reception rolled back in case of listener -execution failure. Sending a response message (via `SessionAwareMessageListener`) will -be part of the same local transaction, but any other resource operations (such as -database access) will operate independently. This usually requires duplicate message -detection in the listener implementation, covering the case where database processing +execution failure. Sending a response message (through `SessionAwareMessageListener`) is +part of the same local transaction, but any other resource operations (such as +database access) operate independently. This usually requires duplicate message +detection in the listener implementation, to cover the case where database processing has committed but message processing failed to commit. +Consider the following bean definition: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2247,28 +2392,34 @@ has committed but message processing failed to commit. **** ---- +==== -For participating in an externally managed transaction, you will need to configure a -transaction manager and use a listener container which supports externally managed -transactions: typically `DefaultMessageListenerContainer`. +To participate in an externally managed transaction, you need to configure a +transaction manager and use a listener container that supports externally managed +transactions (typically, `DefaultMessageListenerContainer`). -To configure a message listener container for XA transaction participation, you'll want +To configure a message listener container for XA transaction participation, you want to configure a `JtaTransactionManager` (which, by default, delegates to the Java EE -server's transaction subsystem). Note that the underlying JMS ConnectionFactory needs to -be XA-capable and properly registered with your JTA transaction coordinator! (Check your -Java EE server's configuration of JNDI resources.) This allows message reception as well -as e.g. database access to be part of the same transaction (with unified commit +server's transaction subsystem). Note that the underlying JMS `ConnectionFactory` needs to +be XA-capable and properly registered with your JTA transaction coordinator. (Check your +Java EE server's configuration of JNDI resources.) This lets message reception as well +as (for example) database access be part of the same transaction (with unified commit semantics, at the expense of XA transaction log overhead). +The following bean definition creates a transaction manager: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -Then you just need to add it to our earlier container configuration. The container will -take care of the rest. +Then we need to add it to our earlier container configuration. The container +takes care of the rest. The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2276,9 +2427,11 @@ take care of the rest. - **** + <1> ---- +<1> Our transaction manager. +==== @@ -2286,11 +2439,12 @@ take care of the rest. === Support for JCA Message Endpoints Beginning with version 2.5, Spring also provides support for a JCA-based -`MessageListener` container. The `JmsMessageEndpointManager` will attempt to +`MessageListener` container. The `JmsMessageEndpointManager` tries to automatically determine the `ActivationSpec` class name from the provider's -`ResourceAdapter` class name. Therefore, it is typically possible to just provide -Spring's generic `JmsActivationSpecConfig` as shown in the following example. +`ResourceAdapter` class name. Therefore, it is typically possible to provide +Spring's generic `JmsActivationSpecConfig`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2304,11 +2458,13 @@ Spring's generic `JmsActivationSpecConfig` as shown in the following example. ---- +==== -Alternatively, you may set up a `JmsMessageEndpointManager` with a given +Alternatively, you can set up a `JmsMessageEndpointManager` with a given `ActivationSpec` object. The `ActivationSpec` object may also come from a JNDI lookup -(using ``). +(using ``). The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2323,10 +2479,12 @@ Alternatively, you may set up a `JmsMessageEndpointManager` with a given ---- +==== -Using Spring's `ResourceAdapterFactoryBean`, the target `ResourceAdapter` may be -configured locally as depicted in the following example. +Using Spring's `ResourceAdapterFactoryBean`, you can configure the target `ResourceAdapter` +locally, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2341,46 +2499,45 @@ configured locally as depicted in the following example. ---- +==== -The specified `WorkManager` may also point to an environment-specific thread pool - -typically through ``SimpleTaskWorkManager``'s "asyncTaskExecutor" property. Consider +The specified `WorkManager` can also point to an environment-specific thread pool -- +typically through a `SimpleTaskWorkManager` instance's `asyncTaskExecutor` property. Consider defining a shared thread pool for all your `ResourceAdapter` instances if you happen to use multiple adapters. -In some environments (e.g. WebLogic 9 or above), the entire `ResourceAdapter` object may -be obtained from JNDI instead (using ``). The Spring-based message -listeners can then interact with the server-hosted `ResourceAdapter`, also using the +In some environments (such as WebLogic 9 or above), you can instead obtain the entire `ResourceAdapter` object +from JNDI (by using ``). The Spring-based message +listeners can then interact with the server-hosted `ResourceAdapter`, which also use the server's built-in `WorkManager`. -Please consult the javadoc for `JmsMessageEndpointManager`, `JmsActivationSpecConfig`, -and `ResourceAdapterFactoryBean` for more details. +See the Javadoc for {api-spring-framework}/jms/listener/endpoint/JmsMessageEndpointManager.html[`JmsMessageEndpointManager`], {api-spring-framework}/jms/listener/endpoint/JmsActivationSpecConfig.html[`JmsActivationSpecConfig`], +and {api-spring-framework}/jca/support/ResourceAdapterFactoryBean.html[`ResourceAdapterFactoryBean`] for more details. -Spring also provides a generic JCA message endpoint manager which is not tied to JMS: +Spring also provides a generic JCA message endpoint manager that is not tied to JMS: `org.springframework.jca.endpoint.GenericMessageEndpointManager`. This component allows -for using any message listener type (e.g. a CCI MessageListener) and any -provider-specific ActivationSpec object. Check out your JCA provider's documentation to -find out about the actual capabilities of your connector, and consult -``GenericMessageEndpointManager``'s javadoc for the Spring-specific configuration details. - -[NOTE] -==== -JCA-based message endpoint management is very analogous to EJB 2.1 Message-Driven Beans; -it uses the same underlying resource provider contract. Like with EJB 2.1 MDBs, any -message listener interface supported by your JCA provider can be used in the Spring -context as well. Spring nevertheless provides explicit 'convenience' support for JMS, -simply because JMS is the most common endpoint API used with the JCA endpoint management +for using any message listener type (such as a CCI `MessageListener`) and any +provider-specific `ActivationSpec` object. See your JCA provider's documentation to +find out about the actual capabilities of your connector, and see +the {api-spring-framework}/jca/endpoint/GenericMessageEndpointManager.html[`GenericMessageEndpointManager`] Javadoc for the Spring-specific configuration details. + +NOTE: JCA-based message endpoint management is very analogous to EJB 2.1 Message-Driven Beans. +It uses the same underlying resource provider contract. As with EJB 2.1 MDBs, you can use any +message listener interface supported by your JCA provider in the Spring +context as well. Spring nevertheless provides explicit "`convenience`" support for JMS, +because JMS is the most common endpoint API used with the JCA endpoint management contract. -==== [[jms-annotated]] -=== Annotation-driven listener endpoints +=== Annotation-driven Listener Endpoints The easiest way to receive a message asynchronously is to use the annotated listener -endpoint infrastructure. In a nutshell, it allows you to expose a method of a managed -bean as a JMS listener endpoint. +endpoint infrastructure. In a nutshell, it lets you expose a method of a managed +bean as a JMS listener endpoint. The following example shows how to use it: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2391,32 +2548,32 @@ bean as a JMS listener endpoint. public void processOrder(String data) { ... } } ---- +==== -The idea of the example above is that whenever a message is available on the -`javax.jms.Destination` "myDestination", the `processOrder` method is invoked -accordingly (in this case, with the content of the JMS message similarly to +The idea of the preceding example is that, whenever a message is available on the +`javax.jms.Destination` `myDestination`, the `processOrder` method is invoked +accordingly (in this case, with the content of the JMS message, similar to what the <> provides). The annotated endpoint infrastructure creates a message listener container -behind the scenes for each annotated method, using a `JmsListenerContainerFactory`. +behind the scenes for each annotated method, by using a `JmsListenerContainerFactory`. Such a container is not registered against the application context but can be easily -located for management purposes using the `JmsListenerEndpointRegistry` bean. +located for management purposes by using the `JmsListenerEndpointRegistry` bean. -[TIP] -==== -`@JmsListener` is a _repeatable_ annotation on Java 8, so it is possible to associate -several JMS destinations to the same method by adding additional `@JmsListener` +TIP: `@JmsListener` is a repeatable annotation on Java 8, so you can associate +several JMS destinations with the same method by adding additional `@JmsListener` declarations to it. -==== + [[jms-annotated-support]] -==== Enable listener endpoint annotations +==== Enable Listener Endpoint Annotations -To enable support for `@JmsListener` annotations add `@EnableJms` to one of -your `@Configuration` classes. +To enable support for `@JmsListener` annotations, you can add `@EnableJms` to one of +your `@Configuration` classes, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2435,20 +2592,22 @@ your `@Configuration` classes. } } ---- +==== By default, the infrastructure looks for a bean named `jmsListenerContainerFactory` as the source for the factory to use to create message listener containers. In this -case, and ignoring the JMS infrastructure setup, the `processOrder` method can be -invoked with a core poll size of 3 threads and a maximum pool size of 10 threads. +case (and ignoring the JMS infrastructure setup), you can invoke the `processOrder` method +with a core poll size of three threads and a maximum pool size of ten threads. -It is possible to customize the listener container factory to use per annotation or -an explicit default can be configured by implementing the `JmsListenerConfigurer` -interface. The default is only required if at least one endpoint is registered -without a specific container factory. See the javadoc for full details and examples. +You can customize the listener container factory to use for each annotation or you can configure +an explicit default by implementing the `JmsListenerConfigurer` +interface. The default is required only if at least one endpoint is registered +without a specific container factory. See the Javadoc of classes that implement {api-spring-framework}/jms/annotation/JmsListenerConfigurer.html[`JmsListenerConfigurer`] for details and examples. -If you prefer <> use the `` -element. +If you prefer <>, you can use the `` +element, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2462,15 +2621,19 @@ element. ---- +==== + [[jms-annotated-programmatic-registration]] -==== Programmatic endpoints registration +==== Programmatic Endpoint Registration -`JmsListenerEndpoint` provides a model of an JMS endpoint and is responsible for configuring -the container for that model. The infrastructure allows you to configure endpoints -programmatically in addition to the ones that are detected by the `JmsListener` annotation. +`JmsListenerEndpoint` provides a model of a JMS endpoint and is responsible for configuring +the container for that model. The infrastructure lets you programmatically configure endpoints +in addition to the ones that are detected by the `JmsListener` annotation. +The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2490,22 +2653,25 @@ programmatically in addition to the ones that are detected by the `JmsListener` } } ---- +==== -In the example above, we used `SimpleJmsListenerEndpoint` which provides the actual -`MessageListener` to invoke but you could just as well build your own endpoint variant -describing a custom invocation mechanism. +In the preceding example, we used `SimpleJmsListenerEndpoint`, which provides the actual +`MessageListener` to invoke. However, you could also build your own endpoint variant +to describe a custom invocation mechanism. + +Note that you could skip the use of `@JmsListener` altogether +and programmatically register only your endpoints through `JmsListenerConfigurer`. -It should be noted that you could just as well skip the use of `@JmsListener` altogether -and only register your endpoints programmatically through `JmsListenerConfigurer`. [[jms-annotated-method-signature]] -==== Annotated endpoint method signature +==== Annotated Endpoint Method Signature -So far, we have been injecting a simple `String` in our endpoint but it can actually -have a very flexible method signature. Let's rewrite it to inject the `Order` with +So far, we have been injecting a simple `String` in our endpoint, but it can actually +have a very flexible method signature. In the follwoing example, we rewrite it to inject the `Order` with a custom header: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2518,43 +2684,47 @@ a custom header: } } ---- +==== -These are the main elements you can inject in JMS listener endpoints: +The main elements you can inject in JMS listener endpoints are as follows: -* The raw `javax.jms.Message` or any of its subclasses (provided of course that it +* The raw `javax.jms.Message` or any of its subclasses (provided that it matches the incoming message type). -* The `javax.jms.Session` for optional access to the native JMS API e.g. for sending - a custom reply. -* The `org.springframework.messaging.Message` representing the incoming JMS message. +* The `javax.jms.Session` for optional access to the native JMS API (for example, for sending + a custom reply). +* The `org.springframework.messaging.Message` that represents the incoming JMS message. Note that this message holds both the custom and the standard headers (as defined by `JmsHeaders`). * `@Header`-annotated method arguments to extract a specific header value, including standard JMS headers. -* `@Headers`-annotated argument that must also be assignable to `java.util.Map` for +* A `@Headers`-annotated argument that must also be assignable to `java.util.Map` for getting access to all headers. -* A non-annotated element that is not one of the supported types (i.e. `Message` and +* A non-annotated element that is not one of the supported types (`Message` or `Session`) is considered to be the payload. You can make that explicit by annotating the parameter with `@Payload`. You can also turn on validation by adding an extra `@Valid`. The ability to inject Spring's `Message` abstraction is particularly useful to benefit from all the information stored in the transport-specific message without relying on -transport-specific API. +transport-specific API. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @JmsListener(destination = "myDestination") public void processOrder(Message order) { ... } ---- +==== -Handling of method arguments is provided by `DefaultMessageHandlerMethodFactory` which can be -further customized to support additional method arguments. The conversion and validation -support can be customized there as well. +Handling of method arguments is provided by `DefaultMessageHandlerMethodFactory`, which you can +further customize to support additional method arguments. You can customize the conversion and validation +support there as well. For instance, if we want to make sure our `Order` is valid before processing it, we can -annotate the payload with `@Valid` and configure the necessary validator as follows: +annotate the payload with `@Valid` and configure the necessary validator, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2575,21 +2745,24 @@ annotate the payload with `@Valid` and configure the necessary validator as foll } } ---- +==== + [[jms-annotated-response]] -==== Response management +==== Response Management -The existing support in <> -already allows your method to have a non-`void` return type. When that's the case, the result of -the invocation is encapsulated in a `javax.jms.Message` sent either in the destination specified +The existing support in <> +already lets your method have a non-`void` return type. When that is the case, the result of +the invocation is encapsulated in a `javax.jms.Message`, sent either in the destination specified in the `JMSReplyTo` header of the original message or in the default destination configured on -the listener. That default destination can now be set using the `@SendTo` annotation of the +the listener. You can now set that default destination by using the `@SendTo` annotation of the messaging abstraction. -Assuming our `processOrder` method should now return an `OrderStatus`, it is possible to write it -as follow to automatically send a response: +Assuming that our `processOrder` method should now return an `OrderStatus`, we can write it +to automatically send a response, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2600,16 +2773,15 @@ as follow to automatically send a response: return status; } ---- - -[TIP] ==== -If you have several `@JmsListener`-annotated methods, you can also place the `@SendTo` + +TIP: If you have several `@JmsListener`-annotated methods, you can also place the `@SendTo` annotation at the class level to share a default reply destination. -==== -If you need to set additional headers in a transport-independent manner, you could return a -`Message` instead, something like: +If you need to set additional headers in a transport-independent manner, you can return a +`Message` instead, with a method similar to the following: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2623,11 +2795,13 @@ If you need to set additional headers in a transport-independent manner, you cou .build(); } ---- +==== If you need to compute the response destination at runtime, you can encapsulate your response -in a `JmsResponse` instance that also provides the destination to use at runtime. The previous -example can be rewritten as follows: +in a `JmsResponse` instance that also provides the destination to use at runtime. We can rewrite the previous +example as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2641,10 +2815,13 @@ example can be rewritten as follows: return JmsResponse.forQueue(response, "status"); } ---- +==== -Finally if you need to specify some QoS values for the response such as the priority or -the time to live, you can configure the `JmsListenerContainerFactory` accordingly: +Finally, if you need to specify some QoS values for the response such as the priority or +the time to live, you can configure the `JmsListenerContainerFactory` accordingly, +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -2664,22 +2841,24 @@ the time to live, you can configure the `JmsListenerContainerFactory` accordingl } } ---- +==== [[jms-namespace]] -=== JMS namespace support +=== JMS Namespace Support Spring provides an XML namespace for simplifying JMS configuration. To use the JMS -namespace elements you will need to reference the JMS schema: +namespace elements, you need to reference the JMS schema, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd **http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd**"> @@ -2688,13 +2867,16 @@ namespace elements you will need to reference the JMS schema: ---- +<1> Referencing the JMS schema. +==== The namespace consists of three top-level elements: ``, `` -and ``. ``. `` enables the use of <>. `` and `` -defines shared listener container configuration and may contain `` child elements. Here -is an example of a basic configuration for two listeners. +define shared listener container configuration and can contain `` child elements. The +following example shows a basic configuration for two listeners: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2706,12 +2888,13 @@ is an example of a basic configuration for two listeners. ---- +==== -The example above is equivalent to creating two distinct listener container bean -definitions and two distinct `MessageListenerAdapter` bean definitions as demonstrated +The preceding example is equivalent to creating two distinct listener container bean +definitions and two distinct `MessageListenerAdapter` bean definitions, as shown in <>. In addition to the attributes shown -above, the `listener` element may contain several optional ones. The following table -describes all available attributes: +in the preceding example, the `listener` element can contain several optional ones. The following table +describes all of the available attributes: [[jms-namespace-listener-tbl]] .Attributes of the JMS element @@ -2719,50 +2902,52 @@ describes all available attributes: |=== | Attribute | Description -| id -| A bean name for the hosting listener container. If not specified, a bean name will be +| `id` +| A bean name for the hosting listener container. If not specified, a bean name is automatically generated. -| destination __(required)__ +| `destination` (required) | The destination name for this listener, resolved through the `DestinationResolver` strategy. -| ref __(required)__ +| `ref` (required) | The bean name of the handler object. -| method -| The name of the handler method to invoke. If the `ref` points to a `MessageListener` - or Spring `SessionAwareMessageListener`, this attribute may be omitted. +| `method` +| The name of the handler method to invoke. If the `ref` attribute points to a `MessageListener` + or Spring `SessionAwareMessageListener`, you can omit this attribute. -| response-destination -| The name of the default response destination to send response messages to. This will - be applied in case of a request message that does not carry a "JMSReplyTo" field. The - type of this destination will be determined by the listener-container's - "response-destination-type" attribute. Note: This only applies to a listener method with a - return value, for which each result object will be converted into a response message. +| `response-destination` +| The name of the default response destination to which to send response messages. This is + applied in case of a request message that does not carry a `JMSReplyTo` field. The + type of this destination is determined by the listener-container's + `response-destination-type` attribute. Note that this applies only to a listener method with a + return value, for which each result object is converted into a response message. -| subscription +| `subscription` | The name of the durable subscription, if any. -| selector +| `selector` | An optional message selector for this listener. -| concurrency -| The number of concurrent sessions/consumers to start for this listener. Can either be - a simple number indicating the maximum number (e.g. "5") or a range indicating the lower - as well as the upper limit (e.g. "3-5"). Note that a specified minimum is just a hint - and might be ignored at runtime. Default is the value provided by the container +| `concurrency` +| The number of concurrent sessions or consumers to start for this listener. This value can either be + a simple number indicating the maximum number (for example, `5`) or a range indicating the lower + as well as the upper limit (for example, `3-5`). Note that a specified minimum is only a hint + and might be ignored at runtime. The default is the value provided by the container. |=== The `` element also accepts several optional attributes. This allows for customization of the various strategies (for example, `taskExecutor` and -`destinationResolver`) as well as basic JMS settings and resource references. Using -these attributes, it is possible to define highly-customized listener containers while +`destinationResolver`) as well as basic JMS settings and resource references. By using +these attributes, you can define highly-customized listener containers while still benefiting from the convenience of the namespace. -Such settings can be automatically exposed as a `JmsListenerContainerFactory` by -specifying the id of the bean to expose through the `factory-id` attribute. +You can automatically expose such settings as a `JmsListenerContainerFactory` by +specifying the `id` of the bean to expose through the `factory-id` attribute, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2778,10 +2963,11 @@ specifying the id of the bean to expose through the `factory-id` attribute. ---- +==== -The following table describes all available attributes. Consult the class-level javadocs -of the `AbstractMessageListenerContainer` and its concrete subclasses for more details -on the individual properties. The javadocs also provide a discussion of transaction +The following table describes all available attributes. See the class-level Javadoc +of the {api-spring-framework}/jms/listener/AbstractMessageListenerContainer.html[`AbstractMessageListenerContainer`] and its concrete subclasses for more details +on the individual properties. The Javadoc also provides a discussion of transaction choices and message redelivery scenarios. [[jms-namespace-listener-container-tbl]] @@ -2790,106 +2976,108 @@ choices and message redelivery scenarios. |=== | Attribute | Description -| container-type -| The type of this listener container. Available options are: `default`, `simple`, - `default102`, or `simple102` (the default value is `'default'`). +| `container-type` +| The type of this listener container. The available options are `default`, `simple`, + `default102`, or `simple102` (the default option is `default`). -| container-class -| A custom listener container implementation class as fully qualified class name. - Default is Spring's standard `DefaultMessageListenerContainer` or - `SimpleMessageListenerContainer`, according to the "container-type" attribute. +| `container-class` +| A custom listener container implementation class as a fully qualified class name. + The default is Spring's standard `DefaultMessageListenerContainer` or + `SimpleMessageListenerContainer`, according to the `container-type` attribute. -| factory-id +| `factory-id` | Exposes the settings defined by this element as a `JmsListenerContainerFactory` - with the specified id so that they can be reused with other endpoints. + with the specified `id` so that they can be reused with other endpoints. -| connection-factory +| `connection-factory` | A reference to the JMS `ConnectionFactory` bean (the default bean name is - `'connectionFactory'`). + `connectionFactory`). -| task-executor +| `task-executor` | A reference to the Spring `TaskExecutor` for the JMS listener invokers. -| destination-resolver -| A reference to the `DestinationResolver` strategy for resolving JMS `Destinations`. +| `destination-resolver` +| A reference to the `DestinationResolver` strategy for resolving JMS `Destination` instances. -| message-converter +| `message-converter` | A reference to the `MessageConverter` strategy for converting JMS Messages to listener - method arguments. Default is a `SimpleMessageConverter`. + method arguments. The default is a `SimpleMessageConverter`. -| error-handler -| A reference to an `ErrorHandler` strategy for handling any uncaught Exceptions that +| `error-handler` +| A reference to an `ErrorHandler` strategy for handling any uncaught exceptions that may occur during the execution of the `MessageListener`. -| destination-type -| The JMS destination type for this listener: `queue`, `topic`, `durableTopic`, `sharedTopic` - or `sharedDurableTopic`. This enables potentially the `pubSubDomain`, `subscriptionDurable` - and `subscriptionShared` properties of the container. The default is `queue` (i.e. disabling - those 3 properties). +| `destination-type` +| The JMS destination type for this listener: `queue`, `topic`, `durableTopic`, `sharedTopic`, + or `sharedDurableTopic`. This potentially enables the `pubSubDomain`, `subscriptionDurable` + and `subscriptionShared` properties of the container. The default is `queue` (which disables + those three properties). -| response-destination-type -| The JMS destination type for responses: "queue", "topic". Default is the value of the - "destination-type" attribute. +| `response-destination-type` +| The JMS destination type for responses: `queue` or `topic`. The default is the value of the + `destination-type` attribute. -| client-id -| The JMS client id for this listener container. Needs to be specified when using +| `client-id` +| The JMS client ID for this listener container. You must specify it when you use durable subscriptions. -| cache -| The cache level for JMS resources: `none`, `connection`, `session`, `consumer` or - `auto`. By default ( `auto`), the cache level will effectively be "consumer", unless - an external transaction manager has been specified - in which case the effective - default will be `none` (assuming Java EE-style transaction management where the given +| `cache` +| The cache level for JMS resources: `none`, `connection`, `session`, `consumer`, or + `auto`. By default (`auto`), the cache level is effectively `consumer`, unless + an external transaction manager has been specified -- in which case, the effective + default will be `none` (assuming Java EE-style transaction management, where the given ConnectionFactory is an XA-aware pool). -| acknowledge -| The native JMS acknowledge mode: `auto`, `client`, `dups-ok` or `transacted`. A value - of `transacted` activates a locally transacted `Session`. As an alternative, specify - the `transaction-manager` attribute described below. Default is `auto`. +| `acknowledge` +| The native JMS acknowledge mode: `auto`, `client`, `dups-ok`, or `transacted`. A value + of `transacted` activates a locally transacted `Session`. As an alternative, you can specify + the `transaction-manager` attribute, described later in table. The default is `auto`. -| transaction-manager +| `transaction-manager` | A reference to an external `PlatformTransactionManager` (typically an XA-based - transaction coordinator, e.g. Spring's `JtaTransactionManager`). If not specified, - native acknowledging will be used (see "acknowledge" attribute). - -| concurrency -| The number of concurrent sessions/consumers to start for each listener. Can either be - a simple number indicating the maximum number (e.g. "5") or a range indicating the - lower as well as the upper limit (e.g. "3-5"). Note that a specified minimum is just a - hint and might be ignored at runtime. Default is 1; keep concurrency limited to 1 in - case of a topic listener or if queue ordering is important; consider raising it for + transaction coordinator, such as Spring's `JtaTransactionManager`). If not specified, + native acknowledging is used (see the `acknowledge` attribute). + +| `concurrency` +| The number of concurrent sessions or consumers to start for each listener. It can either be + a simple number indicating the maximum number (for example, `5`) or a range indicating the + lower as well as the upper limit (for example, `3-5`). Note that a specified minimum is just a + hint and might be ignored at runtime. The default is `1`. You should keep concurrency limited to `1` in + case of a topic listener or if queue ordering is important. Consider raising it for general queues. -| prefetch +| `prefetch` | The maximum number of messages to load into a single session. Note that raising this - number might lead to starvation of concurrent consumers! + number might lead to starvation of concurrent consumers. -| receive-timeout -| The timeout to use for receive calls (in milliseconds). The default is `1000` ms (1 - sec); `-1` indicates no timeout at all. +| `receive-timeout` +| The timeout (in milliseconds) to use for receive calls. The default is `1000` (one + second). `-1` indicates no timeout. -| back-off -| Specify the `BackOff` instance to use to compute the interval between recovery +| `back-off` +| Specifies the `BackOff` instance to use to compute the interval between recovery attempts. If the `BackOffExecution` implementation returns `BackOffExecution#STOP`, - the listener container will not further attempt to recover. The `recovery-interval` + the listener container does not further try to recover. The `recovery-interval` value is ignored when this property is set. The default is a `FixedBackOff` with - an interval of 5000 ms, that is 5 seconds. + an interval of 5000 milliseconds (that is, five seconds). -| recovery-interval -| Specify the interval between recovery attempts, in milliseconds. Convenience +| `recovery-interval` +| Specifies the interval between recovery attempts, in milliseconds. It offers a convenient way to create a `FixedBackOff` with the specified interval. For more recovery - options, consider specifying a BackOff instance instead. The default is 5000 ms, - that is 5 seconds. + options, consider specifying a `BackOff` instance instead. The default is 5000 milliseconds + (that is, five seconds). -| phase +| `phase` | The lifecycle phase within which this container should start and stop. The lower the - value the earlier this container will start and the later it will stop. The default is - `Integer.MAX_VALUE` meaning the container will start as late as possible and stop as + value, the earlier this container starts and the later it stops. The default is + `Integer.MAX_VALUE`, meaning that the container starts as late as possible and stops as soon as possible. |=== -Configuring a JCA-based listener container with the "jms" schema support is very similar. +Configuring a JCA-based listener container with the `jms` schema support is very similar, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -2902,9 +3090,9 @@ Configuring a JCA-based listener container with the "jms" schema support is very ---- +==== -The available configuration options for the JCA variant are described in the following -table: +The following table describes the available configuration options for the JCA variant: [[jms-namespace-jca-listener-container-tbl]] .Attributes of the JMS element @@ -2912,104 +3100,99 @@ table: |=== | Attribute | Description -| factory-id +| `factory-id` | Exposes the settings defined by this element as a `JmsListenerContainerFactory` - with the specified id so that they can be reused with other endpoints. + with the specified `id` so that they can be reused with other endpoints. -| resource-adapter +| `resource-adapter` | A reference to the JCA `ResourceAdapter` bean (the default bean name is - `'resourceAdapter'`). + `resourceAdapter`). -| activation-spec-factory +| `activation-spec-factory` | A reference to the `JmsActivationSpecFactory`. The default is to autodetect the JMS - provider and its `ActivationSpec` class (see `DefaultJmsActivationSpecFactory`) + provider and its `ActivationSpec` class (see {api-spring-framework}/jms/listener/endpoint/DefaultJmsActivationSpecFactory.html[`DefaultJmsActivationSpecFactory`]). -| destination-resolver +| `destination-resolver` | A reference to the `DestinationResolver` strategy for resolving JMS `Destinations`. -| message-converter +| `message-converter` | A reference to the `MessageConverter` strategy for converting JMS Messages to listener - method arguments. Default is a `SimpleMessageConverter`. + method arguments. The default is `SimpleMessageConverter`. -| destination-type -| The JMS destination type for this listener: `queue`, `topic`, `durableTopic`, `sharedTopic` - or `sharedDurableTopic`. This enables potentially the `pubSubDomain`, `subscriptionDurable` - and `subscriptionShared` properties of the container. The default is `queue` (i.e. disabling - those 3 properties). +| `destination-type` +| The JMS destination type for this listener: `queue`, `topic`, `durableTopic`, `sharedTopic`. + or `sharedDurableTopic`. This potentially enables the `pubSubDomain`, `subscriptionDurable`, + and `subscriptionShared` properties of the container. The default is `queue` (which disables + those three properties). -| response-destination-type -| The JMS destination type for responses: "queue", "topic". Default is the value of the - "destination-type" attribute. +| `response-destination-type` +| The JMS destination type for responses: `queue` or `topic`. The default is the value of the + `destination-type` attribute. -| client-id -| The JMS client id for this listener container. Needs to be specified when using +| `client-id` +| The JMS client ID for this listener container. It needs to be specified when using durable subscriptions. -| acknowledge -| The native JMS acknowledge mode: `auto`, `client`, `dups-ok` or `transacted`. A value - of `transacted` activates a locally transacted `Session`. As an alternative, specify - the `transaction-manager` attribute described below. Default is `auto`. +| `acknowledge` +| The native JMS acknowledge mode: `auto`, `client`, `dups-ok`, or `transacted`. A value + of `transacted` activates a locally transacted `Session`. As an alternative, you can specify + the `transaction-manager` attribute described later. The default is `auto`. -| transaction-manager +| `transaction-manager` | A reference to a Spring `JtaTransactionManager` or a `javax.transaction.TransactionManager` for kicking off an XA transaction for each - incoming message. If not specified, native acknowledging will be used (see the - "acknowledge" attribute). + incoming message. If not specified, native acknowledging is used (see the + `acknowledge` attribute). -| concurrency -| The number of concurrent sessions/consumers to start for each listener. Can either be - a simple number indicating the maximum number (e.g. "5") or a range indicating the - lower as well as the upper limit (e.g. "3-5"). Note that a specified minimum is just a - hint and will typically be ignored at runtime when using a JCA listener container. - Default is 1. +| `concurrency` +| The number of concurrent sessions or consumers to start for each listener. It can either be + a simple number indicating the maximum number (for example `5`) or a range indicating the + lower as well as the upper limit (for example, `3-5`). Note that a specified minimum is only a + hint and is typically ignored at runtime when you use a JCA listener container. + The default is 1. -| prefetch +| `prefetch` | The maximum number of messages to load into a single session. Note that raising this - number might lead to starvation of concurrent consumers! + number might lead to starvation of concurrent consumers. |=== - [[jmx]] == JMX - - -[[jmx-introduction]] -=== Introduction - -The JMX support in Spring provides you with the features to easily and transparently +The JMX (Java Management Extensions) support in Spring provides features that let you easily and transparently integrate your Spring application into a JMX infrastructure. .JMX? **** -This chapter is not an introduction to JMX... it doesn't try to explain the motivations -of why one might want to use JMX (or indeed what the letters JMX actually stand for). If -you are new to JMX, check out <> at the end of this chapter. +This chapter is not an introduction to JMX. It does not try to explain +why you might want to use JMX. If +you are new to JMX, see <> at the end of this chapter. **** Specifically, Spring's JMX support provides four core features: -* The automatic registration of __any__ Spring bean as a JMX MBean -* A flexible mechanism for controlling the management interface of your beans -* The declarative exposure of MBeans over remote, JSR-160 connectors -* The simple proxying of both local and remote MBean resources +* The automatic registration of any Spring bean as a JMX MBean. +* A flexible mechanism for controlling the management interface of your beans. +* The declarative exposure of MBeans over remote, JSR-160 connectors. +* The simple proxying of both local and remote MBean resources. These features are designed to work without coupling your application components to -either Spring or JMX interfaces and classes. Indeed, for the most part your application +either Spring or JMX interfaces and classes. Indeed, for the most part, your application classes need not be aware of either Spring or JMX in order to take advantage of the Spring JMX features. [[jmx-exporting]] -=== Exporting your beans to JMX +=== Exporting Your Beans to JMX The core class in Spring's JMX framework is the `MBeanExporter`. This class is responsible for taking your Spring beans and registering them with a JMX `MBeanServer`. For example, consider the following class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3046,11 +3229,13 @@ For example, consider the following class: } } ---- +==== To expose the properties and methods of this bean as attributes and operations of an -MBean you simply configure an instance of the `MBeanExporter` class in your -configuration file and pass in the bean as shown below: +MBean, you can configure an instance of the `MBeanExporter` class in your +configuration file and pass in the bean, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3069,44 +3254,44 @@ configuration file and pass in the bean as shown below: ---- +==== -The pertinent bean definition from the above configuration snippet is the `exporter` +The pertinent bean definition from the preceding configuration snippet is the `exporter` bean. The `beans` property tells the `MBeanExporter` exactly which of your beans must be exported to the JMX `MBeanServer`. In the default configuration, the key of each entry in the `beans` `Map` is used as the `ObjectName` for the bean referenced by the -corresponding entry value. This behavior can be changed as described in <>. +corresponding entry value. You can change this behavior, as described in <>. -With this configuration the `testBean` bean is exposed as an MBean under the -`ObjectName` `bean:name=testBean1`. By default, all __public__ properties of the bean -are exposed as attributes and all __public__ methods (bar those inherited from the +With this configuration, the `testBean` bean is exposed as an MBean under the +`ObjectName` `bean:name=testBean1`. By default, all `public` properties of the bean +are exposed as attributes and all `public` methods (except those inherited from the `Object` class) are exposed as operations. -[NOTE] -==== -`MBeanExporter` is a `Lifecycle` bean (see <>) and MBeans are exported as late as possible during -the application lifecycle by default. It is possible to configure the `phase` at which +NOTE: `MBeanExporter` is a `Lifecycle` bean (see <>). By default, MBeans are exported as late as possible during +the application lifecycle. You can configure the `phase` at which the export happens or disable automatic registration by setting the `autoStartup` flag. -==== + [[jmx-exporting-mbeanserver]] ==== Creating an MBeanServer -The above configuration assumes that the application is running in an environment that -has one (and only one) `MBeanServer` already running. In this case, Spring will attempt +The configuration shown in the <> assumes that the application is running in an environment that +has one (and only one) `MBeanServer` already running. In this case, Spring tries to locate the running `MBeanServer` and register your beans with that server (if any). -This behavior is useful when your application is running inside a container such as -Tomcat or IBM WebSphere that has its own `MBeanServer`. +This behavior is useful when your application runs inside a container (such as +Tomcat or IBM WebSphere) that has its own `MBeanServer`. -However, this approach is of no use in a standalone environment, or when running inside -a container that does not provide an `MBeanServer`. To address this you can create an +However, this approach is of no use in a standalone environment or when running inside +a container that does not provide an `MBeanServer`. To address this, you can create an `MBeanServer` instance declaratively by adding an instance of the `org.springframework.jmx.support.MBeanServerFactoryBean` class to your configuration. You can also ensure that a specific `MBeanServer` is used by setting the value of the -``MBeanExporter``'s `server` property to the `MBeanServer` value returned by an -`MBeanServerFactoryBean`; for example: +`MBeanExporter` instance's `server` property to the `MBeanServer` value returned by an +`MBeanServerFactoryBean`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3134,23 +3319,26 @@ You can also ensure that a specific `MBeanServer` is used by setting the value o ---- +==== + +In the preceding example, an instance of `MBeanServer` is created by the `MBeanServerFactoryBean` and is +supplied to the `MBeanExporter` through the `server` property. When you supply your own +`MBeanServer` instance, the `MBeanExporter` does not try to locate a running +`MBeanServer` and uses the supplied `MBeanServer` instance. For this to work +correctly, you must have a JMX implementation on your classpath. -Here an instance of `MBeanServer` is created by the `MBeanServerFactoryBean` and is -supplied to the `MBeanExporter` via the server property. When you supply your own -`MBeanServer` instance, the `MBeanExporter` will not attempt to locate a running -`MBeanServer` and will use the supplied `MBeanServer` instance. For this to work -correctly, you must (of course) have a JMX implementation on your classpath. [[jmx-mbean-server]] -==== Reusing an existing MBeanServer +==== Reusing an Existing `MBeanServer` If no server is specified, the `MBeanExporter` tries to automatically detect a running -`MBeanServer`. This works in most environment where only one `MBeanServer` instance is -used, however when multiple instances exist, the exporter might pick the wrong server. -In such cases, one should use the `MBeanServer` `agentId` to indicate which instance to -be used: +`MBeanServer`. This works in most environments, where only one `MBeanServer` instance is +used. However, when multiple instances exist, the exporter might pick the wrong server. +In such cases, you should use the `MBeanServer` `agentId` to indicate which instance to +be used, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3167,11 +3355,14 @@ be used: ---- +==== -For platforms/cases where the existing `MBeanServer` has a dynamic (or unknown) -`agentId` which is retrieved through lookup methods, one should use -<>: +For platforms or cases where the existing `MBeanServer` has a dynamic (or unknown) +`agentId` that is retrieved through lookup methods, you should use +<>, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3187,26 +3378,30 @@ For platforms/cases where the existing `MBeanServer` has a dynamic (or unknown) ---- +==== + [[jmx-exporting-lazy]] -==== Lazy-initialized MBeans +==== Lazily Initialized MBeans -If you configure a bean with the `MBeanExporter` that is also configured for lazy -initialization, then the `MBeanExporter` will __not__ break this contract and will avoid -instantiating the bean. Instead, it will register a proxy with the `MBeanServer` and -will defer obtaining the bean from the container until the first invocation on the proxy +If you configure a bean with an `MBeanExporter` that is also configured for lazy +initialization, the `MBeanExporter` does not break this contract and avoids +instantiating the bean. Instead, it registers a proxy with the `MBeanServer` and +defers obtaining the bean from the container until the first invocation on the proxy occurs. + [[jmx-exporting-auto]] -==== Automatic registration of MBeans +==== Automatic Registration of MBeans Any beans that are exported through the `MBeanExporter` and are already valid MBeans are -registered as-is with the `MBeanServer` without further intervention from Spring. MBeans -can be automatically detected by the `MBeanExporter` by setting the `autodetect` -property to `true`: +registered as-is with the `MBeanServer` without further intervention from Spring. You can cause MBeans +to be automatically detected by the `MBeanExporter` by setting the `autodetect` +property to `true`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3216,26 +3411,28 @@ property to `true`: ---- +==== + +In the preceding example, the bean called `spring:mbean=true` is already a valid JMX MBean and is +automatically registered by Spring. By default, a bean that is autodetected for JMX +registration has its bean name used as the `ObjectName`. You can override this behavior, +as detailed in <>. -Here, the bean called `spring:mbean=true` is already a valid JMX MBean and will be -automatically registered by Spring. By default, beans that are autodetected for JMX -registration have their bean name used as the `ObjectName`. This behavior can be -overridden as detailed in <>. [[jmx-exporting-registration-behavior]] -==== Controlling the registration behavior +==== Controlling the Registration Behavior Consider the scenario where a Spring `MBeanExporter` attempts to register an `MBean` -with an `MBeanServer` using the `ObjectName` `'bean:name=testBean1'`. If an `MBean` +with an `MBeanServer` by using the `ObjectName` `bean:name=testBean1`. If an `MBean` instance has already been registered under that same `ObjectName`, the default behavior is to fail (and throw an `InstanceAlreadyExistsException`). -It is possible to control the behavior of exactly what happens when an `MBean` is +You can control exactly what happens when an `MBean` is registered with an `MBeanServer`. Spring's JMX support allows for three different registration behaviors to control the registration behavior when the registration -process finds that an `MBean` has already been registered under the same `ObjectName`; -these registration behaviors are summarized on the following table: +process finds that an `MBean` has already been registered under the same `ObjectName`. +The following table summarizes these registration behaviors: [[jmx-registration-behaviors]] .Registration Behaviors @@ -3245,32 +3442,33 @@ these registration behaviors are summarized on the following table: | `REGISTRATION_FAIL_ON_EXISTING` | This is the default registration behavior. If an `MBean` instance has already been - registered under the same `ObjectName`, the `MBean` that is being registered will not - be registered and an `InstanceAlreadyExistsException` will be thrown. The existing + registered under the same `ObjectName`, the `MBean` that is being registered is not + registered, and an `InstanceAlreadyExistsException` is thrown. The existing `MBean` is unaffected. | `REGISTRATION_IGNORE_EXISTING` | If an `MBean` instance has already been registered under the same `ObjectName`, the - `MBean` that is being registered will __not__ be registered. The existing `MBean` is - unaffected, and no `Exception` will be thrown. This is useful in settings where + `MBean` that is being registered is not registered. The existing `MBean` is + unaffected, and no `Exception` is thrown. This is useful in settings where multiple applications want to share a common `MBean` in a shared `MBeanServer`. | `REGISTRATION_REPLACE_EXISTING` | If an `MBean` instance has already been registered under the same `ObjectName`, the - existing `MBean` that was previously registered will be unregistered and the new - `MBean` will be registered in its place (the new `MBean` effectively replaces the + existing `MBean` that was previously registered is unregistered, and the new + `MBean` is registered in its place (the new `MBean` effectively replaces the previous instance). |=== -The above values are defined as constants on the `MBeanRegistrationSupport` class (the +The values in the preceding table are defined as constants on the `MBeanRegistrationSupport` class (the `MBeanExporter` class derives from this superclass). If you want to change the default -registration behavior, you simply need to set the value of the +registration behavior, you need to set the value of the `registrationBehaviorName` property on your `MBeanExporter` definition to one of those values. -The following example illustrates how to effect a change from the default registration +The following example shows how to change from the default registration behavior to the `REGISTRATION_REPLACE_EXISTING` behavior: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3292,59 +3490,63 @@ behavior to the `REGISTRATION_REPLACE_EXISTING` behavior: ---- +==== [[jmx-interface]] -=== Controlling the management interface of your beans +=== Controlling the Management Interface of Your Beans -In the previous example, you had little control over the management interface of your -bean; __all__ of the __public__ properties and methods of each exported bean was exposed -as JMX attributes and operations respectively. To exercise finer-grained control over +In the example in the <>, you had little control over the management interface of your +bean. All of the `public` properties and methods of each exported bean were exposed +as JMX attributes and operations, respectively. To exercise finer-grained control over exactly which properties and methods of your exported beans are actually exposed as JMX attributes and operations, Spring JMX provides a comprehensive and extensible mechanism for controlling the management interfaces of your beans. + [[jmx-interface-assembler]] -==== MBeanInfoAssembler interface +==== Using the `MBeanInfoAssembler` Interface Behind the scenes, the `MBeanExporter` delegates to an implementation of the -`org.springframework.jmx.export.assembler.MBeanInfoAssembler` interface which is -responsible for defining the management interface of each bean that is being exposed. +`org.springframework.jmx.export.assembler.MBeanInfoAssembler` interface, which is +responsible for defining the management interface of each bean that is exposed. The default implementation, -`org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler`, simply +`org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler`, defines a management interface that exposes all public properties and methods (as you -saw in the previous examples). Spring provides two additional implementations of the -`MBeanInfoAssembler` interface that allow you to control the generated management -interface using either source-level metadata or any arbitrary interface. +saw in the examples in the preceding sections). Spring provides two additional implementations of the +`MBeanInfoAssembler` interface that let you control the generated management +interface by using either source-level metadata or any arbitrary interface. + [[jmx-interface-metadata]] -==== Using source-level metadata: Java annotations +==== Using Source-level Metadata: Java Annotations -Using the `MetadataMBeanInfoAssembler` you can define the management interfaces for your -beans using source level metadata. The reading of metadata is encapsulated by the +By using the `MetadataMBeanInfoAssembler`, you can define the management interfaces for your +beans by using source-level metadata. The reading of metadata is encapsulated by the `org.springframework.jmx.export.metadata.JmxAttributeSource` interface. Spring JMX -provides a default implementation which uses Java annotations, namely -`org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource`. The -`MetadataMBeanInfoAssembler` __must__ be configured with an implementation instance of -the `JmxAttributeSource` interface for it to function correctly (there is __no__ +provides a default implementation that uses Java annotations, namely +`org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource`. You must configure the +`MetadataMBeanInfoAssembler` with an implementation instance of +the `JmxAttributeSource` interface for it to function correctly (there is no default). To mark a bean for export to JMX, you should annotate the bean class with the -`ManagedResource` annotation. Each method you wish to expose as an operation must be -marked with the `ManagedOperation` annotation and each property you wish to expose must -be marked with the `ManagedAttribute` annotation. When marking properties you can omit +`ManagedResource` annotation. You must mark each method you wish to expose as an operation +with the `ManagedOperation` annotation and mark each property you wish to expose +with the `ManagedAttribute` annotation. When marking properties, you can omit either the annotation of the getter or the setter to create a write-only or read-only -attribute respectively. +attribute, respectively. -NOTE: A `ManagedResource` annotated bean must be public as well as the methods exposing +NOTE: A `ManagedResource`-annotated bean must be public, as must the methods exposing an operation or an attribute. -The example below shows the annotated version of the `JmxTestBean` class that you saw -earlier: +The following example shows the annotated version of the `JmxTestBean` class that we +used in <>: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3405,26 +3607,28 @@ earlier: } ---- +==== -Here you can see that the `JmxTestBean` class is marked with the `ManagedResource` +In the preceding example, you can see that the `JmxTestBean` class is marked with the `ManagedResource` annotation and that this `ManagedResource` annotation is configured with a set of properties. These properties can be used to configure various aspects of the MBean that -is generated by the `MBeanExporter`, and are explained in greater detail later in -section entitled <>. +is generated by the `MBeanExporter` and are explained in greater detail later in +<>. -You will also notice that both the `age` and `name` properties are annotated with the -`ManagedAttribute` annotation, but in the case of the `age` property, only the getter is -marked. This will cause both of these properties to be included in the management -interface as attributes, but the `age` attribute will be read-only. +Both the `age` and `name` properties are annotated with the +`ManagedAttribute` annotation, but, in the case of the `age` property, only the getter is +marked. This causes both of these properties to be included in the management +interface as attributes, but the `age` attribute is read-only. -Finally, you will notice that the `add(int, int)` method is marked with the -`ManagedOperation` attribute whereas the `dontExposeMe()` method is not. This will cause -the management interface to contain only one operation, `add(int, int)`, when using the +Finally, the `add(int, int)` method is marked with the +`ManagedOperation` attribute, whereas the `dontExposeMe()` method is not. This causes +the management interface to contain only one operation (`add(int, int)`) when you use the `MetadataMBeanInfoAssembler`. -The configuration below shows how you configure the `MBeanExporter` to use the +The following configuration shows how you can configure the `MBeanExporter` to use the `MetadataMBeanInfoAssembler`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3456,41 +3660,43 @@ The configuration below shows how you configure the `MBeanExporter` to use the ---- +==== -Here you can see that an `MetadataMBeanInfoAssembler` bean has been configured with an +In the preceding example, an `MetadataMBeanInfoAssembler` bean has been configured with an instance of the `AnnotationJmxAttributeSource` class and passed to the `MBeanExporter` through the assembler property. This is all that is required to take advantage of metadata-driven management interfaces for your Spring-exposed MBeans. + [[jmx-interface-metadata-types]] -==== Source-level metadata types +==== Source-level Metadata Types -The following source level metadata types are available for use in Spring JMX: +The following table describes the source-level metadata types that are available for use in Spring JMX: [[jmx-metadata-types]] .Source-level metadata types |=== | Purpose| Annotation| Annotation Type -| Mark all instances of a `Class` as JMX managed resources +| Mark all instances of a `Class` as JMX managed resources. | `@ManagedResource` | Class -| Mark a method as a JMX operation +| Mark a method as a JMX operation. | `@ManagedOperation` | Method -| Mark a getter or setter as one half of a JMX attribute +| Mark a getter or setter as one half of a JMX attribute. | `@ManagedAttribute` | Method (only getters and setters) -| Define descriptions for operation parameters +| Define descriptions for operation parameters. | `@ManagedOperationParameter` and `@ManagedOperationParameters` | Method |=== -The following configuration parameters are available for use on these source-level +The following table describes the configuration parameters that are available for use on these source-level metadata types: [[jmx-metadata-parameters]] @@ -3500,69 +3706,71 @@ metadata types: | Parameter | Description | Applies to | `ObjectName` -| Used by `MetadataNamingStrategy` to determine the `ObjectName` of a managed resource +| Used by `MetadataNamingStrategy` to determine the `ObjectName` of a managed resource. | `ManagedResource` | `description` -| Sets the friendly description of the resource, attribute or operation -| `ManagedResource`, `ManagedAttribute`, `ManagedOperation`, `ManagedOperationParameter` +| Sets the friendly description of the resource, attribute or operation. +| `ManagedResource`, `ManagedAttribute`, `ManagedOperation`, or `ManagedOperationParameter` | `currencyTimeLimit` -| Sets the value of the `currencyTimeLimit` descriptor field -| `ManagedResource`, `ManagedAttribute` +| Sets the value of the `currencyTimeLimit` descriptor field. +| `ManagedResource` or `ManagedAttribute` | `defaultValue` -| Sets the value of the `defaultValue` descriptor field +| Sets the value of the `defaultValue` descriptor field. | `ManagedAttribute` | `log` -| Sets the value of the `log` descriptor field +| Sets the value of the `log` descriptor field. | `ManagedResource` | `logFile` -| Sets the value of the `logFile` descriptor field +| Sets the value of the `logFile` descriptor field. | `ManagedResource` | `persistPolicy` -| Sets the value of the `persistPolicy` descriptor field +| Sets the value of the `persistPolicy` descriptor field. | `ManagedResource` | `persistPeriod` -| Sets the value of the `persistPeriod` descriptor field +| Sets the value of the `persistPeriod` descriptor field. | `ManagedResource` | `persistLocation` -| Sets the value of the `persistLocation` descriptor field +| Sets the value of the `persistLocation` descriptor field. | `ManagedResource` | `persistName` -| Sets the value of the `persistName` descriptor field +| Sets the value of the `persistName` descriptor field. | `ManagedResource` | `name` -| Sets the display name of an operation parameter +| Sets the display name of an operation parameter. | `ManagedOperationParameter` | `index` -| Sets the index of an operation parameter +| Sets the index of an operation parameter. | `ManagedOperationParameter` |=== + [[jmx-interface-autodetect]] -==== AutodetectCapableMBeanInfoAssembler interface +==== Using the `AutodetectCapableMBeanInfoAssembler` Interface -To simplify configuration even further, Spring introduces the -`AutodetectCapableMBeanInfoAssembler` interface which extends the `MBeanInfoAssembler` +To simplify configuration even further, Spring includes the +`AutodetectCapableMBeanInfoAssembler` interface, which extends the `MBeanInfoAssembler` interface to add support for autodetection of MBean resources. If you configure the -`MBeanExporter` with an instance of `AutodetectCapableMBeanInfoAssembler` then it is -allowed to "vote" on the inclusion of beans for exposure to JMX. +`MBeanExporter` with an instance of `AutodetectCapableMBeanInfoAssembler`, it is +allowed to "`vote`" on the inclusion of beans for exposure to JMX. -Out of the box, the only implementation of the `AutodetectCapableMBeanInfo` interface is -the `MetadataMBeanInfoAssembler` which will vote to include any bean which is marked +The only implementation of the `AutodetectCapableMBeanInfo` interface is +the `MetadataMBeanInfoAssembler`, which votes to include any bean that is marked with the `ManagedResource` attribute. The default approach in this case is to use the -bean name as the `ObjectName` which results in a configuration like this: +bean name as the `ObjectName`, which results in a configuration similar to the following: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3587,31 +3795,34 @@ bean name as the `ObjectName` which results in a configuration like this: ---- +==== -Notice that in this configuration no beans are passed to the `MBeanExporter`; however, -the `JmxTestBean` will still be registered since it is marked with the `ManagedResource` +Notice that, in the preceding configuration, no beans are passed to the `MBeanExporter`. However, +the `JmxTestBean` is still registered, since it is marked with the `ManagedResource` attribute and the `MetadataMBeanInfoAssembler` detects this and votes to include it. The only problem with this approach is that the name of the `JmxTestBean` now has business meaning. You can address this issue by changing the default behavior for `ObjectName` creation as defined in <>. + [[jmx-interface-java]] -==== Defining management interfaces using Java interfaces +==== Defining Management Interfaces by Using Java Interfaces In addition to the `MetadataMBeanInfoAssembler`, Spring also includes the -`InterfaceBasedMBeanInfoAssembler` which allows you to constrain the methods and +`InterfaceBasedMBeanInfoAssembler`, which lets you constrain the methods and properties that are exposed based on the set of methods defined in a collection of interfaces. Although the standard mechanism for exposing MBeans is to use interfaces and a simple -naming scheme, the `InterfaceBasedMBeanInfoAssembler` extends this functionality by -removing the need for naming conventions, allowing you to use more than one interface +naming scheme, `InterfaceBasedMBeanInfoAssembler` extends this functionality by +removing the need for naming conventions, letting you use more than one interface and removing the need for your beans to implement the MBean interfaces. -Consider this interface that is used to define a management interface for the -`JmxTestBean` class that you saw earlier: +Consider the following interface, which is used to define a management interface for the +`JmxTestBean` class that we showed earlier: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3631,11 +3842,13 @@ Consider this interface that is used to define a management interface for the } ---- +==== -This interface defines the methods and properties that will be exposed as operations and -attributes on the JMX MBean. The code below shows how to configure Spring JMX to use +This interface defines the methods and properties that are exposed as operations and +attributes on the JMX MBean. The following code shows how to configure Spring JMX to use this interface as the definition for the management interface: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3663,33 +3876,36 @@ this interface as the definition for the management interface: ---- +==== -Here you can see that the `InterfaceBasedMBeanInfoAssembler` is configured to use the +In the preceding example, the `InterfaceBasedMBeanInfoAssembler` is configured to use the `IJmxTestBean` interface when constructing the management interface for any bean. It is important to understand that beans processed by the `InterfaceBasedMBeanInfoAssembler` -are __not__ required to implement the interface used to generate the JMX management +are not required to implement the interface used to generate the JMX management interface. -In the case above, the `IJmxTestBean` interface is used to construct all management -interfaces for all beans. In many cases this is not the desired behavior and you may +In the preceding case, the `IJmxTestBean` interface is used to construct all management +interfaces for all beans. In many cases, this is not the desired behavior, and you may want to use different interfaces for different beans. In this case, you can pass -`InterfaceBasedMBeanInfoAssembler` a `Properties` instance via the `interfaceMappings` +`InterfaceBasedMBeanInfoAssembler` a `Properties` instance through the `interfaceMappings` property, where the key of each entry is the bean name and the value of each entry is a comma-separated list of interface names to use for that bean. If no management interface is specified through either the `managedInterfaces` or -`interfaceMappings` properties, then the `InterfaceBasedMBeanInfoAssembler` will reflect -on the bean and use all of the interfaces implemented by that bean to create the +`interfaceMappings` properties, the `InterfaceBasedMBeanInfoAssembler` reflects +on the bean and uses all of the interfaces implemented by that bean to create the management interface. + [[jmx-interface-methodnames]] -==== Using MethodNameBasedMBeanInfoAssembler +==== Using `MethodNameBasedMBeanInfoAssembler` -The `MethodNameBasedMBeanInfoAssembler` allows you to specify a list of method names -that will be exposed to JMX as attributes and operations. The code below shows a sample -configuration for this: +`MethodNameBasedMBeanInfoAssembler` lets you specify a list of method names +that are exposed to JMX as attributes and operations. The following code shows a sample +configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3708,41 +3924,43 @@ configuration for this: ---- +==== -Here you can see that the methods `add` and `myOperation` will be exposed as JMX -operations and `getName()`, `setName(String)` and `getAge()` will be exposed as the -appropriate half of a JMX attribute. In the code above, the method mappings apply to -beans that are exposed to JMX. To control method exposure on a bean-by-bean basis, use +In the preceding example, you can see that the `add` and `myOperation` methods are exposed as JMX +operations, and `getName()`, `setName(String)`, and `getAge()` are exposed as the +appropriate half of a JMX attribute. In the preceding code, the method mappings apply to +beans that are exposed to JMX. To control method exposure on a bean-by-bean basis, you can use the `methodMappings` property of `MethodNameMBeanInfoAssembler` to map bean names to lists of method names. [[jmx-naming]] -=== Controlling the ObjectNames for your beans +=== Controlling `ObjectName` Instances for Your Beans Behind the scenes, the `MBeanExporter` delegates to an implementation of the -`ObjectNamingStrategy` to obtain ``ObjectName``s for each of the beans it is registering. -The default implementation, `KeyNamingStrategy`, will, by default, use the key of the +`ObjectNamingStrategy` to obtain an `ObjectName` instance for each of the beans it registers. +By default, the default implementation, `KeyNamingStrategy` uses the key of the `beans` `Map` as the `ObjectName`. In addition, the `KeyNamingStrategy` can map the key of the `beans` `Map` to an entry in a `Properties` file (or files) to resolve the `ObjectName`. In addition to the `KeyNamingStrategy`, Spring provides two additional -`ObjectNamingStrategy` implementations: the `IdentityNamingStrategy` that builds an -`ObjectName` based on the JVM identity of the bean and the `MetadataNamingStrategy` that -uses source level metadata to obtain the `ObjectName`. +`ObjectNamingStrategy` implementations: the `IdentityNamingStrategy` (which builds an +`ObjectName` based on the JVM identity of the bean) and the `MetadataNamingStrategy` (which +uses source-level metadata to obtain the `ObjectName`). [[jmx-naming-properties]] -==== Reading ObjectNames from Properties +==== Reading `ObjectName` Instances from Properties You can configure your own `KeyNamingStrategy` instance and configure it to read -``ObjectName``s from a `Properties` instance rather than use bean key. The -`KeyNamingStrategy` will attempt to locate an entry in the `Properties` with a key -corresponding to the bean key. If no entry is found or if the `Properties` instance is -`null` then the bean key itself is used. +`ObjectName` instances from a `Properties` instance rather than use a bean key. The +`KeyNamingStrategy` tries to locate an entry in the `Properties` with a key +that corresponds to the bean key. If no entry is found or if the `Properties` instance is +`null`, the bean key itself is used. -The code below shows a sample configuration for the `KeyNamingStrategy`: +The following code shows a sample configuration for the `KeyNamingStrategy`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3775,25 +3993,28 @@ The code below shows a sample configuration for the `KeyNamingStrategy`: ---- +==== -Here an instance of `KeyNamingStrategy` is configured with a `Properties` instance that +The preceding example configures an instance of `KeyNamingStrategy` with a `Properties` instance that is merged from the `Properties` instance defined by the mapping property and the properties files located in the paths defined by the mappings property. In this -configuration, the `testBean` bean will be given the `ObjectName` `bean:name=testBean1` +configuration, the `testBean` bean is given an `ObjectName` of `bean:name=testBean1`, since this is the entry in the `Properties` instance that has a key corresponding to the bean key. -If no entry in the `Properties` instance can be found then the bean key name is used as +If no entry in the `Properties` instance can be found, the bean key name is used as the `ObjectName`. + [[jmx-naming-metadata]] -==== Using the MetadataNamingStrategy +==== Using `MetadataNamingStrategy` -The `MetadataNamingStrategy` uses the `objectName` property of the `ManagedResource` -attribute on each bean to create the `ObjectName`. The code below shows the +`MetadataNamingStrategy` uses the `objectName` property of the `ManagedResource` +attribute on each bean to create the `ObjectName`. The following code shows the configuration for the `MetadataNamingStrategy`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3822,31 +4043,37 @@ configuration for the `MetadataNamingStrategy`: ---- +==== -If no `objectName` has been provided for the `ManagedResource` attribute, then an -`ObjectName` will be created with the following -format:__[fully-qualified-package-name]:type=[short-classname],name=[bean-name]__. For -example, the generated `ObjectName` for the following bean would be: -__com.foo:type=MyClass,name=myBean__. +If no `objectName` has been provided for the `ManagedResource` attribute, an +`ObjectName` is created with the following +format: _[fully-qualified-package-name]:type=[short-classname],name=[bean-name]_. For +example, the generated `ObjectName` for the following bean would be +`com.example:type=MyClass,name=myBean`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- - + ---- +==== + [[jmx-context-mbeanexport]] -==== Configuring annotation based MBean export +==== Configuring Annotation-based MBean Export -If you prefer using <> to define -your management interfaces, then a convenience subclass of `MBeanExporter` is available: -`AnnotationMBeanExporter`. When defining an instance of this subclass, the -`namingStrategy`, `assembler`, and `attributeSource` configuration is no longer needed, -since it will always use standard Java annotation-based metadata (autodetection is +If you prefer to use <> to define +your management interfaces, a convenience subclass of `MBeanExporter` is available: +`AnnotationMBeanExporter`. When defining an instance of this subclass, you no longer need the +`namingStrategy`, `assembler`, and `attributeSource` configuration, +since it always uses standard Java annotation-based metadata (autodetection is always enabled as well). In fact, rather than defining an `MBeanExporter` bean, an even -simpler syntax is supported by the `@EnableMBeanExport` `@Configuration` annotation. +simpler syntax is supported by the `@EnableMBeanExport` `@Configuration` annotation, +as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3856,22 +4083,26 @@ simpler syntax is supported by the `@EnableMBeanExport` `@Configuration` annotat } ---- +==== -If you prefer XML based configuration the `'context:mbean-export'` element serves the -same purpose. +If you prefer XML-based configuration, the `` element serves the +same purpose and is shown in the following listing: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -You can provide a reference to a particular MBean `server` if necessary, and the +If necessary, you can provide a reference to a particular MBean `server`, and the `defaultDomain` attribute (a property of `AnnotationMBeanExporter`) accepts an alternate -value for the generated MBean `ObjectNames`' domains. This would be used in place of the +value for the generated MBean `ObjectName` domains. This is used in place of the fully qualified package name as described in the previous section on -<>. +<>, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -3881,27 +4112,29 @@ fully qualified package name as described in the previous section on } ---- +==== +The following example shows the XML equivalent of the preceding annotation-based example: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- - -[NOTE] -==== -Do not use interface-based AOP proxies in combination with autodetection of JMX -annotations in your bean classes. Interface-based proxies 'hide' the target class, which -also hides the JMX managed resource annotations. Hence, use target-class proxies in that -case: through setting the 'proxy-target-class' flag on ``, -``, etc. Otherwise, your JMX beans might be silently ignored at -startup... ==== +CAUTION: Do not use interface-based AOP proxies in combination with autodetection of JMX +annotations in your bean classes. Interface-based proxies "`hide`" the target class, which +also hides the JMX-managed resource annotations. Hence, you should use target-class proxies in that +case (through setting the 'proxy-target-class' flag on ``, +`` and so on). Otherwise, your JMX beans might be silently ignored at +startup. + [[jmx-jsr160]] -=== JSR-160 Connectors +=== Using JSR-160 Connectors For remote access, Spring JMX module offers two `FactoryBean` implementations inside the `org.springframework.jmx.support` package for creating both server- and client-side @@ -3909,27 +4142,31 @@ connectors. [[jmx-jsr160-server]] -==== Server-side connectors +==== Server-side Connectors -To have Spring JMX create, start and expose a JSR-160 `JMXConnectorServer` use the +To have Spring JMX create, start, and expose a JSR-160 `JMXConnectorServer`, you can use the following configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -By default `ConnectorServerFactoryBean` creates a `JMXConnectorServer` bound to -`"service:jmx:jmxmp://localhost:9875"`. The `serverConnector` bean thus exposes the +By default, `ConnectorServerFactoryBean` creates a `JMXConnectorServer` bound to +`service:jmx:jmxmp://localhost:9875`. The `serverConnector` bean thus exposes the local `MBeanServer` to clients through the JMXMP protocol on localhost, port 9875. Note -that the JMXMP protocol is marked as optional by the JSR 160 specification: currently, +that the JMXMP protocol is marked as optional by the JSR 160 specification. Currently, the main open-source JMX implementation, MX4J, and the one provided with the JDK -do __not__ support JMXMP. +do not support JMXMP. To specify another URL and register the `JMXConnectorServer` itself with the -`MBeanServer` use the `serviceUrl` and `ObjectName` properties respectively: +`MBeanServer`, you can use the `serviceUrl` and `ObjectName` properties, respectively, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3940,12 +4177,14 @@ To specify another URL and register the `JMXConnectorServer` itself with the value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector"/> ---- +==== -If the `ObjectName` property is set Spring will automatically register your connector -with the `MBeanServer` under that `ObjectName`. The example below shows the full set of -parameters which you can pass to the `ConnectorServerFactoryBean` when creating a -JMXConnector: +If the `ObjectName` property is set, Spring automatically registers your connector +with the `MBeanServer` under that `ObjectName`. The following example shows the full set of +parameters that you can pass to the `ConnectorServerFactoryBean` when creating a +`JMXConnector`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3963,13 +4202,15 @@ JMXConnector: ---- +==== -Note that when using a RMI-based connector you need the lookup service (tnameserv or -rmiregistry) to be started in order for the name registration to complete. If you are -using Spring to export remote services for you via RMI, then Spring will already have -constructed an RMI registry. If not, you can easily start a registry using the following +Note that, when you use a RMI-based connector, you need the lookup service (`tnameserv` or +`rmiregistry`) to be started in order for the name registration to complete. If you +use Spring to export remote services for you through RMI, Spring has already +constructed an RMI registry. If not, you can easily start a registry by using the following snippet of configuration: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3977,14 +4218,17 @@ snippet of configuration: ---- +==== + [[jmx-jsr160-client]] -==== Client-side connectors +==== Client-side Connectors -To create an `MBeanServerConnection` to a remote JSR-160 enabled `MBeanServer` use the -`MBeanServerConnectionFactoryBean` as shown below: +To create an `MBeanServerConnection` to a remote JSR-160-enabled `MBeanServer`, you can use the +`MBeanServerConnectionFactoryBean`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -3992,17 +4236,21 @@ To create an `MBeanServerConnection` to a remote JSR-160 enabled `MBeanServer` u ---- +==== + [[jmx-jsr160-protocols]] ==== JMX over Hessian or SOAP JSR-160 permits extensions to the way in which communication is done between the client -and the server. The examples above are using the mandatory RMI-based implementation +and the server. The examples shown in the preceding sections use the mandatory RMI-based implementation required by the JSR-160 specification (IIOP and JRMP) and the (optional) JMXMP. By using other providers or JMX implementations (such as http://mx4j.sourceforge.net[MX4J]) you -can take advantage of protocols like SOAP or Hessian over simple HTTP or SSL and others: +can take advantage of protocols such as SOAP or Hessian over simple HTTP or SSL and others, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4011,20 +4259,22 @@ can take advantage of protocols like SOAP or Hessian over simple HTTP or SSL and ---- +==== -In the case of the above example, MX4J 3.0.0 was used; see the official MX4J +In the preceding example, we used MX4J 3.0.0. See the official MX4J documentation for more information. [[jmx-proxy]] -=== Accessing MBeans via proxies +=== Accessing MBeans through Proxies -Spring JMX allows you to create proxies that re-route calls to MBeans registered in a -local or remote `MBeanServer`. These proxies provide you with a standard Java interface -through which you can interact with your MBeans. The code below shows how to configure a +Spring JMX lets you create proxies that re-route calls to MBeans that are registered in a +local or remote `MBeanServer`. These proxies provide you with a standard Java interface, +through which you can interact with your MBeans. The following code shows how to configure a proxy for an MBean running in a local `MBeanServer`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4033,18 +4283,20 @@ proxy for an MBean running in a local `MBeanServer`: ---- +==== -Here you can see that a proxy is created for the MBean registered under the -`ObjectName`: `bean:name=testBean`. The set of interfaces that the proxy will implement -is controlled by the `proxyInterfaces` property and the rules for mapping methods and +In the preceding example, you can see that a proxy is created for the MBean registered under the +`ObjectName` of `bean:name=testBean`. The set of interfaces that the proxy implements +is controlled by the `proxyInterfaces` property, and the rules for mapping methods and properties on these interfaces to operations and attributes on the MBean are the same rules used by the `InterfaceBasedMBeanInfoAssembler`. -The `MBeanProxyFactoryBean` can create a proxy to any MBean that is accessible via an +The `MBeanProxyFactoryBean` can create a proxy to any MBean that is accessible through an `MBeanServerConnection`. By default, the local `MBeanServer` is located and used, but -you can override this and provide an `MBeanServerConnection` pointing to a remote -`MBeanServer` to cater for proxies pointing to remote MBeans: +you can override this and provide an `MBeanServerConnection` that points to a remote +`MBeanServer` to cater for proxies that point to remote MBeans: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4059,11 +4311,12 @@ you can override this and provide an `MBeanServerConnection` pointing to a remot ---- +==== -Here you can see that we create an `MBeanServerConnection` pointing to a remote machine -using the `MBeanServerConnectionFactoryBean`. This `MBeanServerConnection` is then -passed to the `MBeanProxyFactoryBean` via the `server` property. The proxy that is -created will forward all invocations to the `MBeanServer` via this +In the preceding example, we create an `MBeanServerConnection` that points to a remote machine +that uses the `MBeanServerConnectionFactoryBean`. This `MBeanServerConnection` is then +passed to the `MBeanProxyFactoryBean` through the `server` property. The proxy that is +created forwards all invocations to the `MBeanServer` through this `MBeanServerConnection`. @@ -4075,14 +4328,16 @@ Spring's JMX offering includes comprehensive support for JMX notifications. [[jmx-notifications-listeners]] -==== Registering listeners for notifications +==== Registering Listeners for Notifications -Spring's JMX support makes it very easy to register any number of +Spring's JMX support makes it easy to register any number of `NotificationListeners` with any number of MBeans (this includes MBeans exported by -Spring's `MBeanExporter` and MBeans registered via some other mechanism). By way of an -example, consider the scenario where one would like to be informed (via a -`Notification`) each and every time an attribute of a target MBean changes. +Spring's `MBeanExporter` and MBeans registered through some other mechanism). For +example, consider the scenario where one would like to be informed (through a +`Notification`) each and every time an attribute of a target MBean changes. The following +example writes notifications to the console: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4107,7 +4362,12 @@ example, consider the scenario where one would like to be informed (via a } ---- +==== +The following example adds `ConsoleLoggingNotificationListener` (defined in the preceding +example) to `notificationListenerMappings`: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4135,15 +4395,18 @@ example, consider the scenario where one would like to be informed (via a ---- +==== -With the above configuration in place, every time a JMX `Notification` is broadcast from -the target MBean ( `bean:name=testBean1`), the `ConsoleLoggingNotificationListener` bean -that was registered as a listener via the `notificationListenerMappings` property will -be notified. The `ConsoleLoggingNotificationListener` bean can then take whatever action +With the preceding configuration in place, every time a JMX `Notification` is broadcast from +the target MBean (`bean:name=testBean1`), the `ConsoleLoggingNotificationListener` bean +that was registered as a listener through the `notificationListenerMappings` property is +notified. The `ConsoleLoggingNotificationListener` bean can then take whatever action it deems appropriate in response to the `Notification`. -You can also use straight bean names as the link between exported beans and listeners: +You can also use straight bean names as the link between exported beans and listeners, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4171,12 +4434,14 @@ You can also use straight bean names as the link between exported beans and list ---- +==== -If one wants to register a single `NotificationListener` instance for all of the beans -that the enclosing `MBeanExporter` is exporting, one can use the special wildcard `'{asterisk}'` -(sans quotes) as the key for an entry in the `notificationListenerMappings` property -map; for example: +If you want to register a single `NotificationListener` instance for all of the beans +that the enclosing `MBeanExporter` exports, you can use the special wildcard (`{asterisk}`) +as the key for an entry in the `notificationListenerMappings` property +map, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4188,20 +4453,22 @@ map; for example: ---- +==== -If one needs to do the inverse (that is, register a number of distinct listeners against -an MBean), then one has to use the `notificationListeners` list property instead (and in +If you need to do the inverse (that is, register a number of distinct listeners against +an MBean), you must instead use the `notificationListeners` list property (in preference to the `notificationListenerMappings` property). This time, instead of -configuring simply a `NotificationListener` for a single MBean, one configures -`NotificationListenerBean` instances... a `NotificationListenerBean` encapsulates a +configuring a `NotificationListener` for a single MBean, we configure +`NotificationListenerBean` instances. A `NotificationListenerBean` encapsulates a `NotificationListener` and the `ObjectName` (or `ObjectNames`) that it is to be registered against in an `MBeanServer`. The `NotificationListenerBean` also encapsulates -a number of other properties such as a `NotificationFilter` and an arbitrary handback +a number of other properties, such as a `NotificationFilter` and an arbitrary handback object that can be used in advanced JMX notification scenarios. The configuration when using `NotificationListenerBean` instances is not wildly -different to what was presented previously: +different to what was presented previously, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4236,14 +4503,14 @@ different to what was presented previously: ---- +==== -The above example is equivalent to the first notification example. Lets assume then that -we want to be given a handback object every time a `Notification` is raised, and that -additionally we want to filter out extraneous `Notifications` by supplying a -`NotificationFilter`. (For a full discussion of just what a handback object is, and -indeed what a `NotificationFilter` is, please do consult that section of the JMX -specification (1.2) entitled 'The JMX Notification Model'.) +The preceding example is equivalent to the first notification example. Assume, then, that +we want to be given a handback object every time a `Notification` is raised and that +we also want to filter out extraneous `Notifications` by supplying a +`NotificationFilter`. The following example accomplishes these goals: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4293,49 +4560,53 @@ specification (1.2) entitled 'The JMX Notification Model'.) ---- +==== + +(For a full discussion of what a handback object is and, +indeed, what a `NotificationFilter` is, see the section of the JMX +specification (1.2) entitled 'The JMX Notification Model'.) + [[jmx-notifications-publishing]] ==== Publishing Notifications -Spring provides support not just for registering to receive `Notifications`, but also +Spring provides support not only for registering to receive `Notifications` but also for publishing `Notifications`. -[NOTE] -==== -Please note that this section is really only relevant to Spring managed beans that have -been exposed as MBeans via an `MBeanExporter`; any existing, user-defined MBeans should +NOTE: This section is really only relevant to Spring-managed beans that have +been exposed as MBeans through an `MBeanExporter`. Any existing user-defined MBeans should use the standard JMX APIs for notification publication. -==== The key interface in Spring's JMX notification publication support is the `NotificationPublisher` interface (defined in the `org.springframework.jmx.export.notification` package). Any bean that is going to be -exported as an MBean via an `MBeanExporter` instance can implement the related +exported as an MBean through an `MBeanExporter` instance can implement the related `NotificationPublisherAware` interface to gain access to a `NotificationPublisher` -instance. The `NotificationPublisherAware` interface simply supplies an instance of a -`NotificationPublisher` to the implementing bean via a simple setter method, which the +instance. The `NotificationPublisherAware` interface supplies an instance of a +`NotificationPublisher` to the implementing bean through a simple setter method, which the bean can then use to publish `Notifications`. -As stated in the javadocs of the `NotificationPublisher` class, managed beans that are -publishing events via the `NotificationPublisher` mechanism are __not__ responsible for -the state management of any notification listeners and the like ... Spring's JMX support -will take care of handling all the JMX infrastructure issues. All one need do as an -application developer is implement the `NotificationPublisherAware` interface and start -publishing events using the supplied `NotificationPublisher` instance. Note that the -`NotificationPublisher` will be set __after__ the managed bean has been registered with +As stated in the {api-spring-framework}/jmx/export/notification/NotificationPublisher.html[Javadoc of the `NotificationPublisher` interface], managed beans that +publish events through the `NotificationPublisher` mechanism are not responsible for +the state management of any notification listeners. Spring's JMX support +takes care of handling all the JMX infrastructure issues. All you need to do, as an +application developer, is implement the `NotificationPublisherAware` interface and start +publishing events by using the supplied `NotificationPublisher` instance. Note that the +`NotificationPublisher` is set after the managed bean has been registered with an `MBeanServer`. -Using a `NotificationPublisher` instance is quite straightforward... one simply creates +Using a `NotificationPublisher` instance is quite straightforward. You create a JMX `Notification` instance (or an instance of an appropriate `Notification` -subclass), populates the notification with the data pertinent to the event that is to be -published, and one then invokes the `sendNotification(Notification)` on the +subclass), populate the notification with the data pertinent to the event that is to be +published, and invoke the `sendNotification(Notification)` on the `NotificationPublisher` instance, passing in the `Notification`. -Find below a simple example... in this scenario, exported instances of the `JmxTestBean` -are going to publish a `NotificationEvent` every time the `add(int, int)` operation is -invoked. +In the following example, exported instances of the `JmxTestBean` +publish a `NotificationEvent` every time the `add(int, int)` operation is +invoked: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4370,127 +4641,130 @@ invoked. } ---- +==== The `NotificationPublisher` interface and the machinery to get it all working is one of -the nicer features of Spring's JMX support. It does however come with the price tag of -coupling your classes to both Spring and JMX; as always, the advice here is to be -pragmatic... if you need the functionality offered by the `NotificationPublisher` and +the nicer features of Spring's JMX support. It does, however, come with the price tag of +coupling your classes to both Spring and JMX. As always, the advice here is to be +pragmatic. If you need the functionality offered by the `NotificationPublisher` and you can accept the coupling to both Spring and JMX, then do so. [[jmx-resources]] -=== Further resources +=== Further Resources -This section contains links to further resources about JMX. +This section contains links to further resources about JMX: * The http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX -homepage] at Oracle +homepage] at Oracle. * The http://jcp.org/aboutJava/communityprocess/final/jsr003/index3.html[JMX - specification] (JSR-000003) + specification] (JSR-000003). * The http://jcp.org/aboutJava/communityprocess/final/jsr160/index.html[JMX Remote API - specification] (JSR-000160) -* The http://mx4j.sourceforge.net/[MX4J homepage] (an Open Source implementation of - various JMX specs) - + specification] (JSR-000160). +* The http://mx4j.sourceforge.net/[MX4J homepage]. (MX4Jan is an open-source implementation of + various JMX specs.) [[cci]] == JCA CCI - - -[[cci-introduction]] -=== Introduction - Java EE provides a specification to standardize access to enterprise information systems (EIS): the JCA (Java EE Connector Architecture). This specification is divided into -several different parts: +two different parts: -* SPI (Service provider interfaces) that the connector provider must implement. These - interfaces constitute a resource adapter which can be deployed on a Java EE +* SPI (Service Provider Interfaces) that the connector provider must implement. These + interfaces constitute a resource adapter that can be deployed on a Java EE application server. In such a scenario, the server manages connection pooling, - transaction and security (managed mode). The application server is also responsible + transactions, and security (managed mode). The application server is also responsible for managing the configuration, which is held outside the client application. A - connector can be used without an application server as well; in this case, the + connector can be used without an application server as well. In this case, the application must configure it directly (non-managed mode). * CCI (Common Client Interface) that an application can use to interact with the - connector and thus communicate with an EIS. An API for local transaction demarcation + connector and, thus, communicate with an EIS. An API for local transaction demarcation is provided as well. The aim of the Spring CCI support is to provide classes to access a CCI connector in -typical Spring style, leveraging the Spring Framework's general resource and transaction +typical Spring style, using the Spring Framework's general resource and transaction management facilities. -[NOTE] -==== -The client side of connectors doesn't alway use CCI. Some connectors expose their own -APIs, only providing JCA resource adapter to use the system contracts of a Java EE -container (connection pooling, global transactions, security). Spring does not offer +NOTE: The client side of connectors does not alway use CCI. Some connectors expose their own +APIs, providing a JCA resource adapter to use the system contracts of a Java EE +container (connection pooling, global transactions, and security). Spring does not offer special support for such connector-specific APIs. -==== [[cci-config]] === Configuring CCI +This section covers how to configure a Common Client Interface (CCI). It includes the +following topics: + +* <> +* <> +* <> +* <> + + [[cci-config-connector]] -==== Connector configuration +==== Connector Configuration The base resource to use JCA CCI is the `ConnectionFactory` interface. The connector -used must provide an implementation of this interface. +you use must provide an implementation of this interface. To use your connector, you can deploy it on your application server and fetch the `ConnectionFactory` from the server's JNDI environment (managed mode). The connector must be packaged as a RAR file (resource adapter archive) and contain a `ra.xml` file to describe its deployment characteristics. The actual name of the resource is specified -when you deploy it. To access it within Spring, simply use Spring's -`JndiObjectFactoryBean` / `` fetch the factory by its JNDI name. +when you deploy it. To access it within Spring, you can use Spring's +`JndiObjectFactoryBean` or `` to fetch the factory by its JNDI name. -Another way to use a connector is to embed it in your application (non-managed mode), -not using an application server to deploy and configure it. Spring offers the -possibility to configure a connector as a bean, through a provided `FactoryBean` ( -`LocalConnectionFactoryBean`). In this manner, you only need the connector library in +Another way to use a connector is to embed it in your application (non-managed mode) and +not use an application server to deploy and configure it. Spring offers the +possibility to configure a connector as a bean, through a `FactoryBean` implementation called +(`LocalConnectionFactoryBean`). In this manner, you only need the connector library in the classpath (no RAR file and no `ra.xml` descriptor needed). The library must be extracted from the connector's RAR file, if necessary. -Once you have got access to your `ConnectionFactory` instance, you can inject it into +Once you have access to your `ConnectionFactory` instance, you can inject it into your components. These components can either be coded against the plain CCI API or -leverage Spring's support classes for CCI access (e.g. `CciTemplate`). +use Spring's support classes for CCI access (e.g. `CciTemplate`). -[NOTE] -==== -When you use a connector in non-managed mode, you can't use global transactions because -the resource is never enlisted / delisted in the current global transaction of the -current thread. The resource is simply not aware of any global Java EE transactions that +NOTE: When you use a connector in non-managed mode, you cannot use global transactions, because +the resource is never enlisted or delisted in the current global transaction of the +current thread. The resource is not aware of any global Java EE transactions that might be running. -==== + [[cci-config-connectionfactory]] -==== ConnectionFactory configuration in Spring +==== `ConnectionFactory` Configuration in Spring -In order to make connections to the EIS, you need to obtain a `ConnectionFactory` from -the application server if you are in a managed mode, or directly from Spring if you are -in a non-managed mode. +To make connections to the EIS, you need to obtain a `ConnectionFactory` from +the application server (if you are in a managed mode) or directly from Spring (if you are +in a non-managed mode). -In a managed mode, you access a `ConnectionFactory` from JNDI; its properties will be -configured in the application server. +In managed mode, you can access a `ConnectionFactory` from JNDI. Its properties are +configured in the application server. The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== In non-managed mode, you must configure the `ConnectionFactory` you want to use in the configuration of Spring as a JavaBean. The `LocalConnectionFactoryBean` class offers this setup style, passing in the `ManagedConnectionFactory` implementation of your -connector, exposing the application-level CCI `ConnectionFactory`. +connector, exposing the application-level CCI `ConnectionFactory`. The following example +shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4504,29 +4778,30 @@ connector, exposing the application-level CCI `ConnectionFactory`. ---- - -[NOTE] ==== -You can't directly instantiate a specific `ConnectionFactory`. You need to go through + +NOTE: You cannot directly instantiate a specific `ConnectionFactory`. You need to go through the corresponding implementation of the `ManagedConnectionFactory` interface for your connector. This interface is part of the JCA SPI specification. -==== + [[cci-config-cci-connections]] -==== Configuring CCI connections +==== Configuring CCI Connections -JCA CCI allow the developer to configure the connections to the EIS using the -`ConnectionSpec` implementation of your connector. In order to configure its properties, +JCA CCI lets you configure the connections to the EIS by using the +`ConnectionSpec` implementation of your connector. To configure its properties, you need to wrap the target connection factory with a dedicated adapter, -`ConnectionSpecConnectionFactoryAdapter`. So, the dedicated `ConnectionSpec` can be -configured with the property `connectionSpec` (as an inner bean). +`ConnectionSpecConnectionFactoryAdapter`. You can configure the dedicated `ConnectionSpec` +with the `connectionSpec` property (as an inner bean). -This property is not mandatory because the CCI `ConnectionFactory` interface defines two -different methods to obtain a CCI connection. Some of the `ConnectionSpec` properties -can often be configured in the application server (in managed mode) or on the -corresponding local `ManagedConnectionFactory` implementation. +This property is not mandatory, because the CCI `ConnectionFactory` interface defines two +different methods to obtain a CCI connection. You can often configure some of the `ConnectionSpec` properties +in the application server (in managed mode) or on the +corresponding local `ManagedConnectionFactory` implementation. The following listing +shows the relevant parts of the `ConnectionFactory` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4537,12 +4812,15 @@ corresponding local `ManagedConnectionFactory` implementation. ... } ---- +==== -Spring provides a `ConnectionSpecConnectionFactoryAdapter` that allows for specifying a +Spring provides a `ConnectionSpecConnectionFactoryAdapter` that lets you specify a `ConnectionSpec` instance to use for all operations on a given factory. If the adapter's `connectionSpec` property is specified, the adapter uses the `getConnection` variant -with the `ConnectionSpec` argument, otherwise the variant without argument. +with the `ConnectionSpec` argument. Otherwise, the adapter uses the variant without that argument. +The following example shows how to configure a `ConnectionSpecConnectionFactoryAdapter`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4568,17 +4846,21 @@ with the `ConnectionSpec` argument, otherwise the variant without argument. ---- +==== + [[cci-config-single-connection]] -==== Using a single CCI connection +==== Using a Single CCI Connection If you want to use a single CCI connection, Spring provides a further `ConnectionFactory` adapter to manage this. The `SingleConnectionFactory` adapter class -will open a single connection lazily and close it when this bean is destroyed at -application shutdown. This class will expose special `Connection` proxies that behave -accordingly, all sharing the same underlying physical connection. +lazily opens a single connection and closes it when this bean is destroyed at +application shutdown. This class exposes special `Connection` proxies that behave +accordingly, all sharing the same underlying physical connection. The following example +shows how to use the `SingleConnectionFactory` adapter class: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4599,33 +4881,45 @@ accordingly, all sharing the same underlying physical connection. ---- - -[NOTE] ==== -This `ConnectionFactory` adapter cannot directly be configured with a `ConnectionSpec`. -Use an intermediary `ConnectionSpecConnectionFactoryAdapter` that the + +NOTE: This `ConnectionFactory` adapter cannot directly be configured with a `ConnectionSpec`. +You can use an intermediary `ConnectionSpecConnectionFactoryAdapter` that the `SingleConnectionFactory` talks to if you require a single connection for a specific `ConnectionSpec`. -==== [[cci-using]] -=== Using Spring's CCI access support +=== Using Spring's CCI Access Support + +This section describes how to use Spring's support for CCI to achieve various purposes. It +includes the following topics: + +* <> +* <> +* <> +* <> +* <> +* <> +* <> + [[cci-record-creator]] -==== Record conversion +==== Record Conversion -One of the aims of the JCA CCI support is to provide convenient facilities for -manipulating CCI records. The developer can specify the strategy to create records and -extract datas from records, for use with Spring's `CciTemplate`. The following -interfaces will configure the strategy to use input and output records if you don't want +One of the aims of Spring's JCA CCI support is to provide convenient facilities for +manipulating CCI records. You can specify the strategy to create records and +extract datas from records, for use with Spring's `CciTemplate`. The +interfaces described in this section configure the strategy to use input and output records if you do not want to work with records directly in your application. -In order to create an input `Record`, the developer can use a dedicated implementation -of the `RecordCreator` interface. +To create an input `Record`, you can use a dedicated implementation +of the `RecordCreator` interface. The following listing shows the `RecordCreator` +interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4635,13 +4929,15 @@ of the `RecordCreator` interface. } ---- +==== -As you can see, the `createRecord(..)` method receives a `RecordFactory` instance as +The `createRecord(..)` method receives a `RecordFactory` instance as a parameter, which corresponds to the `RecordFactory` of the `ConnectionFactory` used. -This reference can be used to create `IndexedRecord` or `MappedRecord` instances. The -following sample shows how to use the `RecordCreator` interface and indexed/mapped -records. +You can use this reference to create `IndexedRecord` or `MappedRecord` instances. The +following sample shows how to use the `RecordCreator` interface and indexed or mapped +records: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4655,11 +4951,14 @@ records. } ---- +==== -An output `Record` can be used to receive data back from the EIS. Hence, a specific -implementation of the `RecordExtractor` interface can be passed to Spring's -`CciTemplate` for extracting data from the output `Record`. +You can use an output `Record` to receive data back from the EIS. Hence, you can pass a specific +implementation of the `RecordExtractor` interface to Spring's +`CciTemplate` to extract data from the output `Record`. The following listing shows the +`RecordExtractor` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4669,9 +4968,11 @@ implementation of the `RecordExtractor` interface can be passed to Spring's } ---- +==== -The following sample shows how to use the `RecordExtractor` interface. +The following example shows how to use the `RecordExtractor` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4687,21 +4988,25 @@ The following sample shows how to use the `RecordExtractor` interface. } ---- +==== + [[cci-using-template]] -==== CciTemplate +==== Using `CciTemplate` The `CciTemplate` is the central class of the core CCI support package ( -`org.springframework.jca.cci.core`). It simplifies the use of CCI since it handles the -creation and release of resources. This helps to avoid common errors like forgetting to +`org.springframework.jca.cci.core`). It simplifies the use of CCI, since it handles the +creation and release of resources. This helps to avoid common errors, such as forgetting to always close the connection. It cares for the lifecycle of connection and interaction objects, letting application code focus on generating input records from application data and extracting application data from output records. The JCA CCI specification defines two distinct methods to call operations on an EIS. The -CCI `Interaction` interface provides two execute method signatures: +CCI `Interaction` interface provides two execute method signatures, as the following +listing shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4717,21 +5022,23 @@ CCI `Interaction` interface provides two execute method signatures: } ---- +==== -Depending on the template method called, `CciTemplate` will know which `execute` method +Depending on the template method called, `CciTemplate` knows which `execute` method to call on the interaction. In any case, a correctly initialized `InteractionSpec` instance is mandatory. -`CciTemplate.execute(..)` can be used in two ways: +You can use `CciTemplate.execute(..)` in two ways: -* With direct `Record` arguments. In this case, you simply need to pass the CCI input - record in, and the returned object be the corresponding CCI output record. -* With application objects, using record mapping. In this case, you need to provide +* With direct `Record` arguments. In this case, you need to pass in the CCI input + record, and the returned object is the corresponding CCI output record. +* With application objects, by using record mapping. In this case, you need to provide corresponding `RecordCreator` and `RecordExtractor` instances. -With the first approach, the following methods of the template will be used. These -methods directly correspond to those on the `Interaction` interface. +With the first approach, the following methods (which directly correspond to those on the +`Interaction` interface) of the template are used: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4745,11 +5052,13 @@ methods directly correspond to those on the `Interaction` interface. } ---- +==== With the second approach, we need to specify the record creation and record extraction -strategies as arguments. The interfaces used are those describe in the previous section -on record conversion. The corresponding `CciTemplate` methods are the following: +strategies as arguments. The interfaces used are those describe in the <>. The following listing shows the corresponding `CciTemplate` methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4772,17 +5081,20 @@ on record conversion. The corresponding `CciTemplate` methods are the following: } ---- +==== Unless the `outputRecordCreator` property is set on the template (see the following -section), every method will call the corresponding `execute` method of the CCI -`Interaction` with two parameters: `InteractionSpec` and input `Record`, receiving an -output `Record` as return value. +section), every method calls the corresponding `execute` method of the CCI +`Interaction` with two parameters: `InteractionSpec` and an input `Record`. It receives an +output `Record` as its return value. -`CciTemplate` also provides methods to create `IndexRecord` and `MappedRecord` outside a +`CciTemplate` also provides methods to create `IndexRecord` and `MappedRecord` outside of a `RecordCreator` implementation, through its `createIndexRecord(..)` and -`createMappedRecord(..)` methods. This can be used within DAO implementations to create +`createMappedRecord(..)` methods. You can use this within DAO implementations to create `Record` instances to pass into corresponding `CciTemplate.execute(..)` methods. +The following listing shows the `CciTemplate` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4794,17 +5106,21 @@ output `Record` as return value. } ---- +==== + [[cci-using-dao]] -==== DAO support +==== Using DAO Support -Spring's CCI support provides a abstract class for DAOs, supporting injection of a -`ConnectionFactory` or a `CciTemplate` instances. The name of the class is -`CciDaoSupport`: It provides simple `setConnectionFactory` and `setCciTemplate` methods. -Internally, this class will create a `CciTemplate` instance for a passed-in +Spring's CCI support provides an abstract class for DAOs, supporting injection of a +`ConnectionFactory` or a `CciTemplate` instance. The name of the class is +`CciDaoSupport`. It provides simple `setConnectionFactory` and `setCciTemplate` methods. +Internally, this class creates a `CciTemplate` instance for a passed-in `ConnectionFactory`, exposing it to concrete data access implementations in subclasses. +The following example shows how to use `CciDaoSupport`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4828,32 +5144,36 @@ Internally, this class will create a `CciTemplate` instance for a passed-in } ---- +==== + [[automatic-output-generation]] -==== Automatic output record generation +==== Automatic Output Record Generation -If the connector used only supports the `Interaction.execute(..)` method with input and +If the connector you use supports only the `Interaction.execute(..)` method with input and output records as parameters (that is, it requires the desired output record to be passed in instead of returning an appropriate output record), you can set the `outputRecordCreator` property of the `CciTemplate` to automatically generate an output -record to be filled by the JCA connector when the response is received. This record will -be then returned to the caller of the template. +record to be filled by the JCA connector when the response is received. This record is +then returned to the caller of the template. -This property simply holds an implementation of the `RecordCreator` interface, used for -that purpose. The `RecordCreator` interface has already been discussed in -<>. The `outputRecordCreator` property must be directly specified on -the `CciTemplate`. This could be done in the application code like so: +This property holds an implementation of the <>, to be used for +that purpose. You must directly specity the `outputRecordCreator` property on +the `CciTemplate`. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator()); ---- +==== -Or (recommended) in the Spring configuration, if the `CciTemplate` is configured as a -dedicated bean instance: +Alternatively (and we recommend this approach), in the Spring configuration, if the `CciTemplate` is configured as a +dedicated bean instance, you can define beans in the following fashion: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -4864,16 +5184,15 @@ dedicated bean instance: ---- - -[NOTE] ==== -As the `CciTemplate` class is thread-safe, it will usually be configured as a shared + +NOTE: As the `CciTemplate` class is thread-safe, it is usually configured as a shared instance. -==== + [[template-summary]] -==== Summary +==== `CciTemplate` `Interaction` Summary The following table summarizes the mechanisms of the `CciTemplate` class and the corresponding methods called on the CCI `Interaction` interface: @@ -4882,63 +5201,66 @@ corresponding methods called on the CCI `Interaction` interface: .Usage of Interaction execute methods [cols="3,1,3"] |=== -| CciTemplate method signature | CciTemplate outputRecordCreator property | execute method called on the CCI Interaction +| `CciTemplate` method signature | `CciTemplate` `outputRecordCreator` property | `execute` method called on the CCI Interaction -| Record execute(InteractionSpec, Record) -| not set -| Record execute(InteractionSpec, Record) +| `Record execute(InteractionSpec, Record)` +| Not set +| `Record execute(InteractionSpec, Record)` -| Record execute(InteractionSpec, Record) -| set -| boolean execute(InteractionSpec, Record, Record) +| `Record execute(InteractionSpec, Record)` +| Set +| `boolean execute(InteractionSpec, Record, Record)` | void execute(InteractionSpec, Record, Record) -| not set +| Not set | void execute(InteractionSpec, Record, Record) -| void execute(InteractionSpec, Record, Record) -| set -| void execute(InteractionSpec, Record, Record) +| `void execute(InteractionSpec, Record, Record)` +| Set +| `void execute(InteractionSpec, Record, Record)` -| Record execute(InteractionSpec, RecordCreator) -| not set -| Record execute(InteractionSpec, Record) +| `Record execute(InteractionSpec, RecordCreator)` +| Not set +| `Record execute(InteractionSpec, Record)` -| Record execute(InteractionSpec, RecordCreator) -| set -| void execute(InteractionSpec, Record, Record) +| `Record execute(InteractionSpec, RecordCreator)` +| Set +| `void execute(InteractionSpec, Record, Record)` -| Record execute(InteractionSpec, Record, RecordExtractor) -| not set -| Record execute(InteractionSpec, Record) +| `Record execute(InteractionSpec, Record, RecordExtractor)` +| Not set +| `Record execute(InteractionSpec, Record)` -| Record execute(InteractionSpec, Record, RecordExtractor) -| set -| void execute(InteractionSpec, Record, Record) +| `Record execute(InteractionSpec, Record, RecordExtractor)` +| Set +| `void execute(InteractionSpec, Record, Record)` -| Record execute(InteractionSpec, RecordCreator, RecordExtractor) -| not set -| Record execute(InteractionSpec, Record) +| `Record execute(InteractionSpec, RecordCreator, RecordExtractor)` +| Not set +| `Record execute(InteractionSpec, Record)` -| Record execute(InteractionSpec, RecordCreator, RecordExtractor) -| set -| void execute(InteractionSpec, Record, Record) +| `Record execute(InteractionSpec, RecordCreator, RecordExtractor)` +| Set +| `void execute(InteractionSpec, Record, Record)` |=== + [[cci-straight]] -==== Using a CCI Connection and Interaction directly +==== Using a CCI Connection and an Interaction Directly -`CciTemplate` also offers the possibility to work directly with CCI connections and +`CciTemplate` also lets you work directly with CCI connections and interactions, in the same manner as `JdbcTemplate` and `JmsTemplate`. This is useful when you want to perform multiple operations on a CCI connection or interaction, for example. -The interface `ConnectionCallback` provides a CCI `Connection` as argument, in order to -perform custom operations on it, plus the CCI `ConnectionFactory` which the `Connection` -was created with. The latter can be useful for example to get an associated -`RecordFactory` instance and create indexed/mapped records, for example. +The `ConnectionCallback` interface provides a CCI `Connection` as an argument (to +perform custom operations on it) plus the CCI `ConnectionFactory` with which the `Connection` +was created. The latter can be useful (for example, to get an associated +`RecordFactory` instance and create indexed/mapped records). +The following listing shows the `ConnectionCallback` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4949,10 +5271,13 @@ was created with. The latter can be useful for example to get an associated } ---- +==== -The interface `InteractionCallback` provides the CCI `Interaction`, in order to perform -custom operations on it, plus the corresponding CCI `ConnectionFactory`. +The `InteractionCallback` interface provides the CCI `Interaction` (to perform +custom operations on it) plus the corresponding CCI `ConnectionFactory`. +The following listing shows the `InteractionCallback` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4963,23 +5288,23 @@ custom operations on it, plus the corresponding CCI `ConnectionFactory`. } ---- - -[NOTE] ==== -`InteractionSpec` objects can either be shared across multiple template calls or newly + +NOTE: `InteractionSpec` objects can either be shared across multiple template calls or be newly created inside every callback method. This is completely up to the DAO implementation. -==== + [[cci-template-example]] -==== Example for CciTemplate usage +==== Example of `CciTemplate` Usage -In this section, the usage of the `CciTemplate` will be shown to acces to a CICS with +In this section, we show the usage of the `CciTemplate` to access a CICS with ECI mode, with the IBM CICS ECI connector. -Firstly, some initializations on the CCI `InteractionSpec` must be done to specify which -CICS program to access and how to interact with it. +First, we must do some initializations on the CCI `InteractionSpec` to specify which +CICS program to access and how to interact with it, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -4987,10 +5312,12 @@ CICS program to access and how to interact with it. interactionSpec.setFunctionName("MYPROG"); interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE); ---- +==== -Then the program can use CCI via Spring's template and specify mappings between custom -objects and CCI `Records`. +Then the program can use CCI through Spring's template and specify mappings between custom +objects and CCI `Records`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5019,10 +5346,12 @@ objects and CCI `Records`. } } ---- +==== -As discussed previously, callbacks can be used to work directly on CCI connections or -interactions. +As discussed previously, you can use callbacks to work directly on CCI connections or +interactions. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5044,17 +5373,16 @@ interactions. } ---- - -[NOTE] -==== -With a `ConnectionCallback`, the `Connection` used will be managed and closed by the -`CciTemplate`, but any interactions created on the connection must be managed by the -callback implementation. ==== -For a more specific callback, you can implement an `InteractionCallback`. The passed-in -`Interaction` will be managed and closed by the `CciTemplate` in this case. +NOTE: With a `ConnectionCallback`, the `Connection` used is managed and closed by the +`CciTemplate`, but the callback implementation must manage any interactions created on the +connection. +For a more specific callback, you can implement an `InteractionCallback`. If you do so, the passed-in +`Interaction` is managed and closed by the `CciTemplate`. The following example shows how to do so: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5077,10 +5405,12 @@ For a more specific callback, you can implement an `InteractionCallback`. The pa } ---- +==== -For the examples above, the corresponding configuration of the involved Spring beans -could look like this in non-managed mode: +For the preceding examples, the corresponding configuration of the involved Spring beans +could resemble the following example in non-managed mode: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5099,10 +5429,12 @@ could look like this in non-managed mode: ---- +==== -In managed mode (that is, in a Java EE environment), the configuration could look as -follows: +In managed mode (that is, in a Java EE environment), the configuration could resemble +the followig example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5112,41 +5444,41 @@ follows: ---- +==== [[cci-object]] -=== Modeling CCI access as operation objects +=== Modeling CCI Access as Operation Objects -The `org.springframework.jca.cci.object` package contains support classes that allow you -to access the EIS in a different style: through reusable operation objects, analogous to -Spring's JDBC operation objects (see JDBC chapter). This will usually encapsulate the -CCI API: an application-level input object will be passed to the operation object, so it +The `org.springframework.jca.cci.object` package contains support classes that let you +access the EIS in a different style: through reusable operation objects, analogous to +Spring's JDBC operation objects (see the <>). This usually encapsulates the +CCI API. An application-level input object is passed to the operation object, so it can construct the input record and then convert the received record data to an application-level output object and return it. -[NOTE] -==== -This approach is internally based on the `CciTemplate` class and the -`RecordCreator` / `RecordExtractor` interfaces, reusing the machinery of Spring's core +NOTE: This approach is internally based on the `CciTemplate` class and the +`RecordCreator` or `RecordExtractor` interfaces, reusing the machinery of Spring's core CCI support. -==== + [[cci-object-mapping-record]] -==== MappingRecordOperation +==== Using `MappingRecordOperation` -`MappingRecordOperation` essentially performs the same work as `CciTemplate`, but +`MappingRecordOperation` essentially performs the same work as `CciTemplate` but represents a specific, pre-configured operation as an object. It provides two template -methods to specify how to convert an input object to a input record, and how to convert +methods to specify how to convert an input object to an input record and how to convert an output record to an output object (record mapping): -* `createInputRecord(..)` to specify how to convert an input object to an input `Record` -* `extractOutputData(..)` to specify how to extract an output object from an output +* `createInputRecord(..)`: To specify how to convert an input object to an input `Record` +* `extractOutputData(..)`: To specify how to extract an output object from an output `Record` -Here are the signatures of these methods: +The following listing shows the signatures of these methods: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5168,11 +5500,13 @@ Here are the signatures of these methods: } ---- +==== -Thereafter, in order to execute an EIS operation, you need to use a single execute +Thereafter, ito execute an EIS operation, you need to use a single `execute` method, passing in an application-level input object and receiving an application-level -output object as result: +output object as the result. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5186,12 +5520,14 @@ output object as result: ... } ---- +==== -As you can see, contrary to the `CciTemplate` class, this `execute(..)` method does not -have an `InteractionSpec` as argument. Instead, the `InteractionSpec` is global to the -operation. The following constructor must be used to instantiate an operation object -with a specific `InteractionSpec`: +Contrary to the `CciTemplate` class, this `execute(..)` method does not +have an `InteractionSpec` as an argument. Instead, the `InteractionSpec` is global to the +operation. You must use the following constructor to instantiate an operation object +with a specific `InteractionSpec`. The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5199,19 +5535,23 @@ with a specific `InteractionSpec`: MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec); ... ---- +==== + [[cci-object-mapping-comm-area]] -==== MappingCommAreaOperation +==== Using `MappingCommAreaOperation` -Some connectors use records based on a COMMAREA which represents an array of bytes -containing parameters to send to the EIS and data returned by it. Spring provides a +Some connectors use records based on a COMMAREA, which represents an array of bytes +that contain parameters to send to the EIS and the data returned by it. Spring provides a special operation class for working directly on COMMAREA rather than on records. The `MappingCommAreaOperation` class extends the `MappingRecordOperation` class to provide -such special COMMAREA support. It implicitly uses the `CommAreaRecord` class as input -and output record type, and provides two new methods to convert an input object into an -input COMMAREA and the output COMMAREA into an output object. +this special COMMAREA support. It implicitly uses the `CommAreaRecord` class as the input +and output record type and provides two new methods to convert an input object into an +input COMMAREA and convert the output COMMAREA into an output object. The following +listing shows the relevant method signatures: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5229,10 +5569,12 @@ input COMMAREA and the output COMMAREA into an output object. } ---- +==== + [[cci-automatic-record-gen]] -==== Automatic output record generation +==== Automatic Output Record Generation As every `MappingRecordOperation` subclass is based on CciTemplate internally, the same way to automatically generate output records as with `CciTemplate` is available. Every @@ -5240,6 +5582,7 @@ operation object provides a corresponding `setOutputRecordCreator(..)` method. F further information, see <>. + [[cci-object-summary]] ==== Summary @@ -5249,35 +5592,33 @@ The operation object approach uses records in the same manner as the `CciTemplat .Usage of Interaction execute methods [cols="3,1,3"] |=== -| MappingRecordOperation method signature | MappingRecordOperation outputRecordCreator property | execute method called on the CCI Interaction +| `MappingRecordOperation` method signature | `MappingRecordOperation` `outputRecordCreator` property | `execute` method called on the CCI Interaction -| Object execute(Object) -| not set -| Record execute(InteractionSpec, Record) +| `Object execute(Object)` +| Not set +| `Record execute(InteractionSpec, Record)` -| Object execute(Object) -| set -| boolean execute(InteractionSpec, Record, Record) +| `Object execute(Object)` +| Set +| `boolean execute(InteractionSpec, Record, Record)` |=== [[cci-objects-mappring-record-example]] -==== Example for MappingRecordOperation usage +==== Example of `MappingRecordOperation` Usage -In this section, the usage of the `MappingRecordOperation` will be shown to access a +In this section, we show how to use `MappingRecordOperation` to access a database with the Blackbox CCI connector. -[NOTE] -==== -The original version of this connector is provided by the Java EE SDK (version 1.3), -available from Oracle. -==== +NOTE: The original version of this connector is provided by the Java EE SDK (version 1.3), +which is available from Oracle. -Firstly, some initializations on the CCI `InteractionSpec` must be done to specify which -SQL request to execute. In this sample, we directly define the way to convert the +First, you must do some initializations on the CCI `InteractionSpec` to specify which +SQL request to execute. In the following example, we directly define the way to convert the parameters of the request to a CCI record and the way to convert the CCI result record -to an instance of the `Person` class. +to an instance of the `Person` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5312,11 +5653,14 @@ to an instance of the `Person` class. } } ---- +==== -Then the application can execute the operation object, with the person identifier as -argument. Note that operation object could be set up as shared instance, as it is -thread-safe. +Then the application can execute the operation object, with the person identifier as an +argument. Note that you could set up the operation object as a shared instance, as it is +thread-safe. The following executes the operation object with the person identifier as an +argument: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5329,9 +5673,11 @@ thread-safe. } } ---- +==== -The corresponding configuration of Spring beans could look as follows in non-managed mode: +The corresponding configuration of Spring beans could be as follows in non-managed mode: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5361,10 +5707,12 @@ The corresponding configuration of Spring beans could look as follows in non-man ---- +==== -In managed mode (that is, in a Java EE environment), the configuration could look as +In managed mode (that is, in a Java EE environment), the configuration could be as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5385,17 +5733,20 @@ follows: ---- +==== + [[cci-objects-mapping-comm-area-example]] -==== Example for MappingCommAreaOperation usage +==== Example of `MappingCommAreaOperation` Usage -In this section, the usage of the `MappingCommAreaOperation` will be shown: accessing a +In this section, we show how to use the usage of the `MappingCommAreaOperation` to access a CICS with ECI mode with the IBM CICS ECI connector. -Firstly, the CCI `InteractionSpec` needs to be initialized to specify which CICS program -to access and how to interact with it. +First, we need to initialize the CCI `InteractionSpec` to specify which CICS program +to access and how to interact with it, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5419,10 +5770,12 @@ to access and how to interact with it. } ---- +==== -The abstract `EciMappingOperation` class can then be subclassed to specify mappings -between custom objects and `Records`. +We can then subclass the abstract `EciMappingOperation` class to specify mappings +between custom objects and `Records`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5450,9 +5803,11 @@ between custom objects and `Records`. } ---- +==== -The corresponding configuration of Spring beans could look as follows in non-managed mode: +The corresponding configuration of Spring beans could be as follows in non-managed mode: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5471,10 +5826,12 @@ The corresponding configuration of Spring beans could look as follows in non-man ---- +==== -In managed mode (that is, in a Java EE environment), the configuration could look as +In managed mode (that is, in a Java EE environment), the configuration could be as follows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5484,6 +5841,7 @@ follows: ---- +==== @@ -5492,10 +5850,11 @@ follows: JCA specifies several levels of transaction support for resource adapters. The kind of transactions that your resource adapter supports is specified in its `ra.xml` file. -There are essentially three options: none (for example with CICS EPI connector), local -transactions (for example with a CICS ECI connector), global transactions (for example -with an IMS connector). +There are essentially three options: none (for example, with the CICS EPI connector), local +transactions (for example, with a CICS ECI connector), and global transactions (for example, +with an IMS connector). The following example configures the global option: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5507,18 +5866,20 @@ with an IMS connector). ---- +==== For global transactions, you can use Spring's generic transaction infrastructure to -demarcate transactions, with `JtaTransactionManager` as backend (delegating to the Java +demarcate transactions, with `JtaTransactionManager` as the backend (delegating to the Java EE server's distributed transaction coordinator underneath). For local transactions on a single CCI `ConnectionFactory`, Spring provides a specific -transaction management strategy for CCI, analogous to the `DataSourceTransactionManager` +transaction-management strategy for CCI, analogous to the `DataSourceTransactionManager` for JDBC. The CCI API defines a local transaction object and corresponding local transaction demarcation methods. Spring's `CciLocalTransactionManager` executes such -local CCI transactions, fully compliant with Spring's generic -`PlatformTransactionManager` abstraction. +local CCI transactions in a fashion that is fully compliant with Spring's generic +`PlatformTransactionManager` abstraction. The following example configures a `CciLocalTransactionManager`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5529,63 +5890,61 @@ local CCI transactions, fully compliant with Spring's generic ---- +==== -Both transaction strategies can be used with any of Spring's transaction demarcation +You can use both transaction strategies with any of Spring's transaction demarcation facilities, be it declarative or programmatic. This is a consequence of Spring's generic `PlatformTransactionManager` abstraction, which decouples transaction demarcation from -the actual execution strategy. Simply switch between `JtaTransactionManager` and +the actual execution strategy. You can switch between `JtaTransactionManager` and `CciLocalTransactionManager` as needed, keeping your transaction demarcation as-is. -For more information on Spring's transaction facilities, see the chapter entitled +For more information on Spring's transaction facilities, see <>. - [[mail]] == Email - - -[[mail-introduction]] -=== Introduction +This section describes how to send email with the Spring Framework. .Library dependencies **** The following JAR needs to be on the classpath of your application in order to use -the Spring Framework's email library. +the Spring Framework's email library: -* The https://java.net/projects/javamail/pages/Home[JavaMail] library +* The https://javaee.github.io/javamail/[JavaMail] library This library is freely available on the web -- for example, in Maven Central as `com.sun.mail:javax.mail`. **** The Spring Framework provides a helpful utility library for sending email that shields -the user from the specifics of the underlying mailing system and is responsible for low -level resource handling on behalf of the client. +you from the specifics of the underlying mailing system and is responsible for +low-level resource handling on behalf of the client. The `org.springframework.mail` package is the root level package for the Spring Framework's email support. The central interface for sending emails is the `MailSender` -interface; a simple value object encapsulating the properties of a simple mail such as -__from__ and __to__ (plus many others) is the `SimpleMailMessage` class. This package -also contains a hierarchy of checked exceptions which provide a higher level of -abstraction over the lower level mail system exceptions with the root exception being -`MailException`. Please refer to the javadocs for more information on the rich mail +interface. A simple value object that encapsulates the properties of a simple mail such as +`from` and `to` (plus many others) is the `SimpleMailMessage` class. This package +also contains a hierarchy of checked exceptions that provide a higher level of +abstraction over the lower level mail system exceptions, with the root exception being +`MailException`. See the {api-spring-framework}/mail/MailException.html[Javadoc] for more information on the rich mail exception hierarchy. The `org.springframework.mail.javamail.JavaMailSender` interface adds specialized -__JavaMail__ features such as MIME message support to the `MailSender` interface (from -which it inherits). `JavaMailSender` also provides a callback interface for preparing -a 'MimeMessage', called `org.springframework.mail.javamail.MimeMessagePreparator`. +JavaMail features, such as MIME message support to the `MailSender` interface (from +which it inherits). `JavaMailSender` also provides a callback interface called `org.springframework.mail.javamail.MimeMessagePreparator` for preparing +a `MimeMessage`. [[mail-usage]] === Usage -Let's assume there is a business interface called `OrderManager`: +Assume that we have a business interface called `OrderManager`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5595,14 +5954,20 @@ Let's assume there is a business interface called `OrderManager`: } ---- +==== + +Further assume that we have a requirement stating that an email message with an +order number needs to be generated and sent to a customer who placed the relevant order. -Let us also assume that there is a requirement stating that an email message with an -order number needs to be generated and sent to a customer placing the relevant order. [[mail-usage-simple]] -==== Basic MailSender and SimpleMailMessage usage +==== Basic `MailSender` and `SimpleMailMessage` Usage +The following example shows how to use `MailSender` and `SimpleMailMessage` to send an +email when someone places an order: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5648,9 +6013,11 @@ order number needs to be generated and sent to a customer placing the relevant o } ---- +==== -Find below the bean definitions for the above code: +The following example shows the bean definitions for the preceding code: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -5669,15 +6036,18 @@ Find below the bean definitions for the above code: ---- +==== + [[mail-usage-mime]] -==== Using the JavaMailSender and the MimeMessagePreparator +==== Using `JavaMailSender` and `MimeMessagePreparator` -Here is another implementation of `OrderManager` using the `MimeMessagePreparator` -callback interface. Please note in this case that the `mailSender` property is of type +This section describes another implementation of `OrderManager` that uses the `MimeMessagePreparator` +callback interface. In the following example, the `mailSender` property is of type `JavaMailSender` so that we are able to use the JavaMail `MimeMessage` class: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5725,27 +6095,26 @@ callback interface. Please note in this case that the `mailSender` property is o } ---- - -[NOTE] ==== -The mail code is a crosscutting concern and could well be a candidate for refactoring + +NOTE: The mail code is a crosscutting concern and could well be a candidate for refactoring into a <>, which then could be executed at appropriate joinpoints on the `OrderManager` target. -==== The Spring Framework's mail support ships with the standard JavaMail implementation. -Please refer to the relevant javadocs for more information. +See the relevant Javadoc for more information. [[mail-javamail-mime]] -=== Using the JavaMail MimeMessageHelper +=== Using the JavaMail `MimeMessageHelper` -A class that comes in pretty handy when dealing with JavaMail messages is the -`org.springframework.mail.javamail.MimeMessageHelper` class, which shields you from -having to use the verbose JavaMail API. Using the `MimeMessageHelper` it is pretty easy -to create a `MimeMessage`: +A class that comes in pretty handy when dealing with JavaMail messages is +`org.springframework.mail.javamail.MimeMessageHelper`, which shields you from +having to use the verbose JavaMail API. Using the `MimeMessageHelper`, it is pretty easy +to create a `MimeMessage`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5760,21 +6129,26 @@ to create a `MimeMessage`: sender.send(message); ---- +==== + [[mail-javamail-mime-attachments]] -==== Sending attachments and inline resources +==== Sending Attachments and Inline Resources Multipart email messages allow for both attachments and inline resources. Examples of -inline resources would be images or a stylesheet you want to use in your message, but -that you don't want displayed as an attachment. +inline resources includee an image or a stylesheet that you want to use in your message but +that you do not want displayed as an attachment. + + [[mail-javamail-mime-attachments-attachment]] ===== Attachments The following example shows you how to use the `MimeMessageHelper` to send an email -along with a single JPEG image attachment. +with a single JPEG image attachment: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5795,13 +6169,17 @@ along with a single JPEG image attachment. sender.send(message); ---- +==== + + [[mail-javamail-mime-attachments-inline]] -===== Inline resources +===== Inline Resources The following example shows you how to use the `MimeMessageHelper` to send an email -along with an inline image. +with an inline image: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5823,132 +6201,128 @@ along with an inline image. sender.send(message); ---- - -[WARNING] -==== -Inline resources are added to the `MimeMessage` using the specified `Content-ID` -(`identifier1234` in the above example). The order in which you are adding the text -and the resource are __very__ important. Be sure to __first add the text__ and after -that the resources. If you are doing it the other way around, it won't work! ==== +WARNING: Inline resources are added to the `MimeMessage` by using the specified `Content-ID` +(`identifier1234` in the above example). The order in which you add the text +and the resource are very important. Be sure to first add the text and then +the resources. If you are doing it the other way around, it does not work. + + [[mail-templates]] -==== Creating email content using a templating library +==== Creating Email Content by Using a Templating Library -The code in the previous examples explicitly created the content of the email message, -using methods calls such as `message.setText(..)`. This is fine for simple cases, and it +The code in the examples shown in the previous sections explicitly created the content of the email message, +by using methods calls such as `message.setText(..)`. This is fine for simple cases, and it is okay in the context of the aforementioned examples, where the intent was to show you the very basics of the API. -In your typical enterprise application though, you are not going to create the content -of your emails using the above approach for a number of reasons. +In your typical enterprise application, though, developers often do not create the content +of email messagess by using the previously shown approach for a number of reasons: -* Creating HTML-based email content in Java code is tedious and error prone -* There is no clear separation between display logic and business logic +* Creating HTML-based email content in Java code is tedious and error prone. +* There is no clear separation between display logic and business logic. * Changing the display structure of the email content requires writing Java code, - recompiling, redeploying... + recompiling, redeploying, and so on. -Typically the approach taken to address these issues is to use a template library such -as FreeMarker to define the display structure of email content. This leaves your code +Typically, the approach taken to address these issues is to use a template library (such +as FreeMarker) to define the display structure of email content. This leaves your code tasked only with creating the data that is to be rendered in the email template and -sending the email. It is definitely a best practice for when the content of your emails -becomes even moderately complex, and with the Spring Framework's support classes for -FreeMarker becomes quite easy to do. - +sending the email. It is definitely a best practice when the content of your email messages +becomes even moderately complex, and, with the Spring Framework's support classes for +FreeMarker, it becomes quite easy to do. [[scheduling]] == Task Execution and Scheduling - - -[[scheduling-introduction]] -=== Introduction - -The Spring Framework provides abstractions for asynchronous execution and scheduling of +The Spring Framework provides abstractions for the asynchronous execution and scheduling of tasks with the `TaskExecutor` and `TaskScheduler` interfaces, respectively. Spring also features implementations of those interfaces that support thread pools or delegation to -CommonJ within an application server environment. Ultimately the use of these +CommonJ within an application server environment. Ultimately, the use of these implementations behind the common interfaces abstracts away the differences between Java -SE 5, Java SE 6 and Java EE environments. +SE 5, Java SE 6, and Java EE environments. -Spring also features integration classes for supporting scheduling with the `Timer`, -part of the JDK since 1.3, and the Quartz Scheduler ( http://quartz-scheduler.org[]). -Both of those schedulers are set up using a `FactoryBean` with optional references to +Spring also features integration classes to support scheduling with the `Timer` +(part of the JDK since 1.3) and the Quartz Scheduler ( http://quartz-scheduler.org[]). +You can set up both of those schedulers by using a `FactoryBean` with optional references to `Timer` or `Trigger` instances, respectively. Furthermore, a convenience class for both -the Quartz Scheduler and the `Timer` is available that allows you to invoke a method of +the Quartz Scheduler and the `Timer` is available that lets you invoke a method of an existing target object (analogous to the normal `MethodInvokingFactoryBean` operation). [[scheduling-task-executor]] -=== The Spring TaskExecutor abstraction +=== The Spring `TaskExecutor` Abstraction -Executors are the JDK name for the concept of thread pools. The "executor" naming is +Executors are the JDK name for the concept of thread pools. The "`executor`" naming is due to the fact that there is no guarantee that the underlying implementation is -actually a pool; an executor may be single-threaded or even synchronous. Spring's -abstraction hides implementation details between Java SE and Java EE environments. +actually a pool. An executor may be single-threaded or even synchronous. Spring's +abstraction hides implementation details between the Java SE and Java EE environments. Spring's `TaskExecutor` interface is identical to the `java.util.concurrent.Executor` interface. In fact, originally, its primary reason for existence was to abstract away the need for Java 5 when using thread pools. The interface has a single method -`execute(Runnable task)` that accepts a task for execution based on the semantics +(`execute(Runnable task)`) that accepts a task for execution based on the semantics and configuration of the thread pool. The `TaskExecutor` was originally created to give other Spring components an abstraction for thread pooling where needed. Components such as the `ApplicationEventMulticaster`, JMS's `AbstractMessageListenerContainer`, and Quartz integration all use the `TaskExecutor` abstraction to pool threads. However, if your beans need thread pooling -behavior, it is possible to use this abstraction for your own needs. +behavior, you can also use this abstraction for your own needs. + [[scheduling-task-executor-types]] -==== TaskExecutor types +==== `TaskExecutor` Types -There are a number of pre-built implementations of `TaskExecutor` included with the -Spring distribution. In all likelihood, you should never need to implement your own. -The common out-of-the-box variants are: +Spring includes a number of pre-built implementations of `TaskExecutor`. +In all likelihood, you should never need to implement your own. +The variants that Spring provides are as follows: -* `SyncTaskExecutor` +* `SyncTaskExecutor`: This implementation does not execute invocations asynchronously. Instead, each invocation takes place in the calling thread. It is primarily used in situations - where multi-threading is not necessary such as in simple test cases. -* `SimpleAsyncTaskExecutor` - This implementation does not reuse any threads, rather it starts up a new thread - for each invocation. However, it does support a concurrency limit which will block + where multi-threading is not necessary, such as in simple test cases. +* `SimpleAsyncTaskExecutor`: + This implementation does not reuse any threads. Rather, it starts up a new thread + for each invocation. However, it does support a concurrency limit that blocks any invocations that are over the limit until a slot has been freed up. If you - are looking for true pooling, see `ThreadPoolTaskExecutor` below. -* `ConcurrentTaskExecutor` + are looking for true pooling, see `ThreadPoolTaskExecutor`, later in this list. +* `ConcurrentTaskExecutor`: This implementation is an adapter for a `java.util.concurrent.Executor` instance. - There is an alternative, `ThreadPoolTaskExecutor`, that exposes the `Executor` + There is an alternative (`ThreadPoolTaskExecutor`) that exposes the `Executor` configuration parameters as bean properties. There is rarely a need to use - `ConcurrentTaskExecutor` directly, but if the `ThreadPoolTaskExecutor` is not - flexible enough for your needs, then `ConcurrentTaskExecutor` is an alternative. -* `ThreadPoolTaskExecutor` - This implementation is the most commonly used one. It exposes bean properties for + `ConcurrentTaskExecutor` directly. However, if the `ThreadPoolTaskExecutor` is not + flexible enough for your needs, `ConcurrentTaskExecutor` is an alternative. +* `ThreadPoolTaskExecutor`: + This implementation is most commonly used. It exposes bean properties for configuring a `java.util.concurrent.ThreadPoolExecutor` and wraps it in a `TaskExecutor`. - If you need to adapt to a different kind of `java.util.concurrent.Executor`, it is - recommended that you use a `ConcurrentTaskExecutor` instead. -* `WorkManagerTaskExecutor` + If you need to adapt to a different kind of `java.util.concurrent.Executor`, we + recommend that you use a `ConcurrentTaskExecutor` instead. +* `WorkManagerTaskExecutor`: This implementation uses a CommonJ `WorkManager` as its backing service provider and is the central convenience class for setting up CommonJ-based thread pool - integration on WebLogic/WebSphere within a Spring application context. -* `DefaultManagedTaskExecutor` + integration on WebLogic or WebSphere within a Spring application context. +* `DefaultManagedTaskExecutor`: This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236 - compatible runtime environment such as a Java EE 7+ application server, + compatible runtime environment (such as a Java EE 7+ application server), replacing a CommonJ WorkManager for that purpose. + [[scheduling-task-executor-usage]] -==== Using a TaskExecutor +==== Using a `TaskExecutor` -Spring's `TaskExecutor` implementations are used as simple JavaBeans. In the example -below, we define a bean that uses the `ThreadPoolTaskExecutor` to asynchronously print -out a set of messages. +Spring's `TaskExecutor` implementations are used as simple JavaBeans. In the following example, +we define a bean that uses the `ThreadPoolTaskExecutor` to asynchronously print +out a set of messages: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -5982,14 +6356,15 @@ out a set of messages. } } ---- +==== -As you can see, rather than retrieving a thread from the pool and executing yourself, -you add your `Runnable` to the queue and the `TaskExecutor` uses its internal rules to +As you can see, rather than retrieving a thread from the pool and executing it yourself, +you add your `Runnable` to the queue. Then the `TaskExecutor` uses its internal rules to decide when the task gets executed. -To configure the rules that the `TaskExecutor` will use, simple bean properties have -been exposed. +To configure the rules that the `TaskExecutor` uses, we expose simple bean properties: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6003,15 +6378,18 @@ been exposed. ---- +==== [[scheduling-task-scheduler]] -=== The Spring TaskScheduler abstraction +=== The Spring `TaskScheduler` Abstraction -In addition to the `TaskExecutor` abstraction, Spring 3.0 introduces a `TaskScheduler` +In addition to the `TaskExecutor` abstraction, Spring 3.0 introduced a `TaskScheduler` with a variety of methods for scheduling tasks to run at some point in the future. +The following listing shows the `TaskScheduler` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6040,24 +6418,27 @@ with a variety of methods for scheduling tasks to run at some point in the futur ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); } ---- +==== -The simplest method is the one named 'schedule' that takes a `Runnable` and `Date` only. -That will cause the task to run once after the specified time. All of the other methods +The simplest method is the one named `schedule` that takes only a `Runnable` and a `Date`. +That causes the task to run once after the specified time. All of the other methods are capable of scheduling tasks to run repeatedly. The fixed-rate and fixed-delay -methods are for simple, periodic execution, but the method that accepts a Trigger is +methods are for simple, periodic execution, but the method that accepts a `Trigger` is much more flexible. + [[scheduling-trigger-interface]] -==== Trigger interface +==== `Trigger` Interface The `Trigger` interface is essentially inspired by JSR-236 which, as of Spring 3.0, was not yet officially implemented. The basic idea of the `Trigger` is that execution times may be determined based on past execution outcomes or even arbitrary conditions. If these determinations do take into account the outcome of the preceding execution, that information is available within a `TriggerContext`. The `Trigger` interface itself -is quite simple: +is quite simple, as the following listing shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6066,12 +6447,14 @@ is quite simple: Date nextExecutionTime(TriggerContext triggerContext); } ---- +==== -As you can see, the `TriggerContext` is the most important part. It encapsulates all of -the relevant data, and is open for extension in the future if necessary. The +The `TriggerContext` is the most important part. It encapsulates all of +the relevant data and is open for extension in the future, if necessary. The `TriggerContext` is an interface (a `SimpleTriggerContext` implementation is used by -default). Here you can see what methods are available for `Trigger` implementations. +default). The following listing shows the available methods for `Trigger` implementations. +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6084,53 +6467,58 @@ default). Here you can see what methods are available for `Trigger` implementati Date lastCompletionTime(); } ---- +==== + [[scheduling-trigger-implementations]] -==== Trigger implementations +==== `Trigger` Implementations Spring provides two implementations of the `Trigger` interface. The most interesting one is the `CronTrigger`. It enables the scheduling of tasks based on cron expressions. For -example, the following task is being scheduled to run 15 minutes past each hour but only -during the 9-to-5 "business hours" on weekdays. +example, the following task is scheduled to run 15 minutes past each hour but only +during the 9-to-5 "`business hours`" on weekdays: +==== [source,java,indent=0] [subs="verbatim"] ---- scheduler.schedule(task, new CronTrigger("0 15 9-17 * * MON-FRI")); ---- +==== -The other out-of-the-box implementation is a `PeriodicTrigger` that accepts a fixed +The other implementation is a `PeriodicTrigger` that accepts a fixed period, an optional initial delay value, and a boolean to indicate whether the period should be interpreted as a fixed-rate or a fixed-delay. Since the `TaskScheduler` -interface already defines methods for scheduling tasks at a fixed-rate or with a -fixed-delay, those methods should be used directly whenever possible. The value of the -`PeriodicTrigger` implementation is that it can be used within components that rely on +interface already defines methods for scheduling tasks at a fixed rate or with a +fixed delay, those methods should be used directly whenever possible. The value of the +`PeriodicTrigger` implementation is that you can use it within components that rely on the `Trigger` abstraction. For example, it may be convenient to allow periodic triggers, cron-based triggers, and even custom trigger implementations to be used interchangeably. -Such a component could take advantage of dependency injection so that such `Triggers` -could be configured externally and therefore easily modified or extended. +Such a component could take advantage of dependency injection so that you can configure such `Triggers` +externally and, therefore, easily modify or extend them. + [[scheduling-task-scheduler-implementations]] -==== TaskScheduler implementations +==== `TaskScheduler` implementations As with Spring's `TaskExecutor` abstraction, the primary benefit of the `TaskScheduler` arrangement is that an application's scheduling needs are decoupled from the deployment environment. This abstraction level is particularly relevant when deploying to an application server environment where threads should not be created directly by the application itself. For such scenarios, Spring provides a `TimerManagerTaskScheduler` -delegating to a CommonJ TimerManager on WebLogic/WebSphere as well as a more recent -`DefaultManagedTaskScheduler` delegating to a JSR-236 `ManagedScheduledExecutorService` -in a Java EE 7+ environment, both typically configured with a JNDI lookup. +that delegates to a CommonJ `TimerManager` on WebLogic or WebSphere as well as a more recent +`DefaultManagedTaskScheduler` that delegates to a JSR-236 `ManagedScheduledExecutorService` +in a Java EE 7+ environment. Both are typically configured with a JNDI lookup. Whenever external thread management is not a requirement, a simpler alternative is -a local `ScheduledExecutorService` setup within the application which can be adapted +a local `ScheduledExecutorService` setup within the application, which can be adapted through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a -`ThreadPoolTaskScheduler` which internally delegates to a `ScheduledExecutorService`, -providing common bean-style configuration along the lines of `ThreadPoolTaskExecutor`. +`ThreadPoolTaskScheduler`, which internally delegates to a `ScheduledExecutorService` +to provide common bean-style configuration along the lines of `ThreadPoolTaskExecutor`. These variants work perfectly fine for locally embedded thread pool setups in lenient -application server environments as well, in particular on Tomcat and Jetty. +application server environments, as well -- in particular on Tomcat and Jetty. @@ -6141,12 +6529,14 @@ Spring provides annotation support for both task scheduling and asynchronous met execution. + [[scheduling-enable-annotation-support]] -==== Enable scheduling annotations +==== Enable Scheduling Annotations -To enable support for `@Scheduled` and `@Async` annotations add `@EnableScheduling` and -`@EnableAsync` to one of your `@Configuration` classes: +To enable support for `@Scheduled` and `@Async` annotations, you can add `@EnableScheduling` and +`@EnableAsync` to one of your `@Configuration` classes, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6156,14 +6546,17 @@ To enable support for `@Scheduled` and `@Async` annotations add `@EnableScheduli public class AppConfig { } ---- +==== -You are free to pick and choose the relevant annotations for your application. For -example, if you only need support for `@Scheduled`, simply omit `@EnableAsync`. For more -fine-grained control you can additionally implement the `SchedulingConfigurer` and/or -`AsyncConfigurer` interfaces. See the javadocs for full details. +You can pick and choose the relevant annotations for your application. For +example, if you need only support for `@Scheduled`, you can omit `@EnableAsync`. For more +fine-grained control, you can additionally implement the `SchedulingConfigurer` interface, +the `AsyncConfigurer` interface, or both. See the {api-spring-framework}/scheduling/annotation/SchedulingConfigurer.html[`SchedulingConfigurer`] and {api-spring-framework}/scheduling/annotation/AsyncConfigurer.html[`AsyncConfigurer`] Javadoc for full details. -If you prefer XML configuration use the `` element. +If you prefer XML configuration, you can use the `` element, +as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6171,28 +6564,28 @@ If you prefer XML configuration use the `` element. ---- +==== -Notice with the above XML that an executor reference is provided for handling those +Note that, with the preceding XML, an executor reference is provided for handling those tasks that correspond to methods with the `@Async` annotation, and the scheduler reference is provided for managing those methods annotated with `@Scheduled`. -[NOTE] -==== -The default advice mode for processing `@Async` annotations is "proxy" which allows -for interception of calls through the proxy only; local calls within the same class +NOTE: The default advice mode for processing `@Async` annotations is `proxy` which allows +for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider -switching to "aspectj" mode in combination with compile-time or load-time weaving. -==== +switching to `aspectj` mode in combination with compile-time or load-time weaving. + [[scheduling-annotation-support-scheduled]] -==== The @Scheduled annotation +==== The `@Scheduled` annotation -The `@Scheduled` annotation can be added to a method along with trigger metadata. For -example, the following method would be invoked every 5 seconds with a fixed delay, -meaning that the period will be measured from the completion time of each preceding -invocation. +You can add the `@Scheduled` annotation to a method, along with trigger metadata. For +example, the following method is invoked every five seconds with a fixed delay, +meaning that the period is measured from the completion time of each preceding +invocation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6201,11 +6594,13 @@ invocation. // something that should execute periodically } ---- +==== -If a fixed rate execution is desired, simply change the property name specified within -the annotation. The following would be executed every 5 seconds measured between the -successive start times of each invocation. +If you need a fixed-rate execution, you can change the property name specified within +the annotation. The following method is invoked every five seconds (measured between the +successive start times of each invocation): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6214,10 +6609,13 @@ successive start times of each invocation. // something that should execute periodically } ---- +==== -For fixed-delay and fixed-rate tasks, an initial delay may be specified indicating the -number of milliseconds to wait before the first execution of the method. +For fixed-delay and fixed-rate tasks, you can specify an initial delay by indicating the +number of milliseconds to wait before the first execution of the method, as the following +`fixedRate` example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6226,10 +6624,12 @@ number of milliseconds to wait before the first execution of the method. // something that should execute periodically } ---- +==== -If simple periodic scheduling is not expressive enough, then a cron expression may be -provided. For example, the following will only execute on weekdays. +If simple periodic scheduling is not expressive enough, you ca provide a cron expression. +For example, the following executes only on weekdays: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -6238,16 +6638,14 @@ provided. For example, the following will only execute on weekdays. // something that should execute on weekdays only } ---- - -[TIP] -==== -You can additionally use the `zone` attribute to specify the time zone in which the cron -expression will be resolved. ==== +TIP: You can also use the `zone` attribute to specify the time zone in which the cron +expression is resolved. + Notice that the methods to be scheduled must have void returns and must not expect any -arguments. If the method needs to interact with other objects from the Application -Context, then those would typically have been provided through dependency injection. +arguments. If the method needs to interact with other objects from the application +context, those would typically have been provided through dependency injection. [NOTE] ==== @@ -6256,22 +6654,24 @@ As of Spring Framework 4.3, `@Scheduled` methods are supported on beans of any s Make sure that you are not initializing multiple instances of the same `@Scheduled` annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use `@Configurable` on bean -classes which are annotated with `@Scheduled` and registered as regular Spring beans -with the container: You would get double initialization otherwise, once through the -container and once through the `@Configurable` aspect, with the consequence of each +classes that are annotated with `@Scheduled` and registered as regular Spring beans +with the container. Otherwise, you would get double initialization (once through the +container and once through the `@Configurable` aspect), with the consequence of each `@Scheduled` method being invoked twice. ==== + [[scheduling-annotation-support-async]] -==== The @Async annotation +==== The `@Async` annotation -The `@Async` annotation can be provided on a method so that invocation of that method -will occur asynchronously. In other words, the caller will return immediately upon -invocation and the actual execution of the method will occur in a task that has been -submitted to a Spring `TaskExecutor`. In the simplest case, the annotation may be -applied to a `void`-returning method. +You can provide the `@Async` annotation on a method so that invocation of that method +occurs asynchronously. In other words, the caller returns immediately upon +invocation, while the actual execution of the method occurs in a task that has been +submitted to a Spring `TaskExecutor`. In the simplest case, you can apply the annotation +to a method that returns `void`, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6280,12 +6680,14 @@ applied to a `void`-returning method. // this will be executed asynchronously } ---- +==== Unlike the methods annotated with the `@Scheduled` annotation, these methods can expect -arguments, because they will be invoked in the "normal" way by callers at runtime rather -than from a scheduled task being managed by the container. For example, the following is -a legitimate application of the `@Async` annotation. +arguments, because they are invoked in the "`normal`" way by callers at runtime rather +than from a scheduled task being managed by the container. For example, the following code is +a legitimate application of the `@Async` annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6294,12 +6696,15 @@ a legitimate application of the `@Async` annotation. // this will be executed asynchronously } ---- +==== Even methods that return a value can be invoked asynchronously. However, such methods -are required to have a `Future` typed return value. This still provides the benefit of +are required to have a `Future`-typed return value. This still provides the benefit of asynchronous execution so that the caller can perform other tasks prior to calling -`get()` on that Future. +`get()` on that `Future`. The following example shows how to use `@Async` on a method +that returns a value: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6308,20 +6713,19 @@ asynchronous execution so that the caller can perform other tasks prior to calli // this will be executed asynchronously } ---- - -[TIP] ==== -`@Async` methods may not only declare a regular `java.util.concurrent.Future` return type + +TIP: `@Async` methods may not only declare a regular `java.util.concurrent.Future` return type but also Spring's `org.springframework.util.concurrent.ListenableFuture` or, as of Spring -4.2, JDK 8's `java.util.concurrent.CompletableFuture`: for richer interaction with the +4.2, JDK 8's `java.util.concurrent.CompletableFuture`, for richer interaction with the asynchronous task and for immediate composition with further processing steps. -==== -`@Async` can not be used in conjunction with lifecycle callbacks such as -`@PostConstruct`. To asynchronously initialize Spring beans you currently have to use -a separate initializing Spring bean that invokes the `@Async` annotated method on the -target then. +You can not use `@Async` in conjunction with lifecycle callbacks such as +`@PostConstruct`. To asynchronously initialize Spring beans, you currently have to use +a separate initializing Spring bean that then invokes the `@Async` annotated method on the +target, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6349,24 +6753,25 @@ target then. } ---- - -[NOTE] ==== -There is no direct XML equivalent for `@Async` since such methods should be designed -for asynchronous execution in the first place, not externally re-declared to be async. -However, you may manually set up Spring's `AsyncExecutionInterceptor` with Spring AOP, + +NOTE: There is no direct XML equivalent for `@Async`, since such methods should be designed +for asynchronous execution in the first place, not externally re-declared to be asynchronous. +However, you can manually set up Spring's `AsyncExecutionInterceptor` with Spring AOP, in combination with a custom pointcut. -==== + [[scheduling-annotation-support-qualification]] -==== Executor qualification with @Async +==== Executor Qualification with `@Async` -By default when specifying `@Async` on a method, the executor that will be used is the -one supplied to the 'annotation-driven' element as described above. However, the `value` -attribute of the `@Async` annotation can be used when needing to indicate that an +By default, when specifying `@Async` on a method, the executor that is used is the +one supplied to the "`annotation-driven`" element, as described earlier. However, you can use the `value` +attribute of the `@Async` annotation when you need to indicate that an executor other than the default should be used when executing a given method. +The following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6375,21 +6780,25 @@ executor other than the default should be used when executing a given method. // this will be executed asynchronously by "otherExecutor" } ---- +==== + +In this case, `"otherExecutor"` can be the name of any `Executor` bean in the Spring +container, or it may be the name of a qualifier associated with any `Executor` (for example, as +specified with the `` element or Spring's `@Qualifier` annotation). -In this case, "otherExecutor" may be the name of any `Executor` bean in the Spring -container, or may be the name of a __qualifier__ associated with any `Executor`, e.g. as -specified with the `` element or Spring's `@Qualifier` annotation. [[scheduling-annotation-support-exception]] -==== Exception management with @Async +==== Exception Management with `@Async` -When an `@Async` method has a `Future` typed return value, it is easy to manage -an exception that was thrown during the method execution as this exception will -be thrown when calling `get` on the `Future` result. With a void return type -however, the exception is uncaught and cannot be transmitted. For those cases, an -`AsyncUncaughtExceptionHandler` can be provided to handle such exceptions. +When an `@Async` method has a `Future`-typed return value, it is easy to manage +an exception that was thrown during the method execution, as this exception is +thrown when calling `get` on the `Future` result. With a `void` return type, +however, the exception is uncaught and cannot be transmitted. You can provide an +`AsyncUncaughtExceptionHandler` to handle such exceptions. The following example shows +how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6401,58 +6810,65 @@ however, the exception is uncaught and cannot be transmitted. For those cases, a } } ---- +==== -By default, the exception is simply logged. A custom `AsyncUncaughtExceptionHandler` can -be defined _via_ `AsyncConfigurer` or the `task:annotation-driven` XML element. +By default, the exception is merely logged. You can define a custom `AsyncUncaughtExceptionHandler` +by using `AsyncConfigurer` or the `` XML element. [[scheduling-task-namespace]] -=== The task namespace +=== The `task` Namespace -Beginning with Spring 3.0, there is an XML namespace for configuring `TaskExecutor` and +As of version 3.0, Spring includes an XML namespace for configuring `TaskExecutor` and `TaskScheduler` instances. It also provides a convenient way to configure tasks to be scheduled with a trigger. [[scheduling-task-namespace-scheduler]] -==== The 'scheduler' element +==== The 'scheduler' Element -The following element will create a `ThreadPoolTaskScheduler` instance with the -specified thread pool size. +The following element creates a `ThreadPoolTaskScheduler` instance with the +specified thread pool size: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -The value provided for the 'id' attribute will be used as the prefix for thread names -within the pool. The 'scheduler' element is relatively straightforward. If you do not -provide a 'pool-size' attribute, the default thread pool will only have a single thread. +The value provided for the `id` attribute is used as the prefix for thread names +within the pool. The `scheduler` element is relatively straightforward. If you do not +provide a `pool-size` attribute, the default thread pool has only a single thread. There are no other configuration options for the scheduler. [[scheduling-task-namespace-executor]] -==== The 'executor' element +==== The `executor` Element -The following will create a `ThreadPoolTaskExecutor` instance: +The following creates a `ThreadPoolTaskExecutor` instance: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -As with the scheduler above, the value provided for the 'id' attribute will be used as +As with the scheduler shown in the <>, the value provided for the `id` attribute is used as the prefix for thread names within the pool. As far as the pool size is concerned, the -'executor' element supports more configuration options than the 'scheduler' element. For +`executor` element supports more configuration options than the `scheduler` element. For one thing, the thread pool for a `ThreadPoolTaskExecutor` is itself more configurable. -Rather than just a single size, an executor's thread pool may have different values for -the __core__ and the __max__ size. If a single value is provided then the executor will -have a fixed-size thread pool (the core and max sizes are the same). However, the -'executor' element's 'pool-size' attribute also accepts a range in the form of "min-max". +Rather than only a single size, an executor's thread pool can have different values for +the core and the max size. If you provide a single value, the executor +has a fixed-size thread pool (the core and max sizes are the same). However, the +`executor` element's `pool-size` attribute also accepts a range in the form of `min-max`. +The following example sets a minimum value of `5` and a maximum value of `25`: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6461,46 +6877,50 @@ have a fixed-size thread pool (the core and max sizes are the same). However, th pool-size="5-25" queue-capacity="100"/> ---- +==== -As you can see from that configuration, a 'queue-capacity' value has also been provided. +In the preceding configuration, a `queue-capacity` value has also been provided. The configuration of the thread pool should also be considered in light of the executor's queue capacity. For the full description of the relationship between pool -size and queue capacity, consult the documentation for -http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html[ThreadPoolExecutor]. -The main idea is that when a task is submitted, the executor will first try to use a +size and queue capacity, see the documentation for +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html[`ThreadPoolExecutor`]. +The main idea is that, when a task is submitted, the executor first tries to use a free thread if the number of active threads is currently less than the core size. If the -core size has been reached, then the task will be added to the queue as long as its -capacity has not yet been reached. Only then, if the queue's capacity __has__ been -reached, will the executor create a new thread beyond the core size. If the max size has -also been reached, then the executor will reject the task. +core size has been reached, the task is added to the queue, as long as its +capacity has not yet been reached. Only then, if the queue's capacity has been +reached, does the executor create a new thread beyond the core size. If the max size has +also been reached, then the executor rejects the task. -By default, the queue is __unbounded__, but this is rarely the desired configuration, +By default, the queue is unbounded, but this is rarely the desired configuration, because it can lead to `OutOfMemoryErrors` if enough tasks are added to that queue while -all pool threads are busy. Furthermore, if the queue is unbounded, then the max size has -no effect at all. Since the executor will always try the queue before creating a new +all pool threads are busy. Furthermore, if the queue is unbounded, the max size has +no effect at all. Since the executor always tries the queue before creating a new thread beyond the core size, a queue must have a finite capacity for the thread pool to -grow beyond the core size (this is why a __fixed size__ pool is the only sensible case +grow beyond the core size (this is why a fixed-size pool is the only sensible case when using an unbounded queue). -In a moment, we will review the effects of the keep-alive setting which adds yet another -factor to consider when providing a pool size configuration. First, let's consider the +Consider the case, as mentioned above, when a task is rejected. By default, when a task is rejected, -a thread pool executor will throw a `TaskRejectedException`. However, the rejection +a thread pool executor throws a `TaskRejectedException`. However, the rejection policy is actually configurable. The exception is thrown when using the default -rejection policy which is the `AbortPolicy` implementation. For applications where some -tasks can be skipped under heavy load, either the `DiscardPolicy` or -`DiscardOldestPolicy` may be configured instead. Another option that works well for +rejection policy, which is the `AbortPolicy` implementation. For applications where some +tasks can be skipped under heavy load, you can instead configure either `DiscardPolicy` or +`DiscardOldestPolicy`. Another option that works well for applications that need to throttle the submitted tasks under heavy load is the `CallerRunsPolicy`. Instead of throwing an exception or discarding tasks, that policy -will simply force the thread that is calling the submit method to run the task itself. -The idea is that such a caller will be busy while running that task and not able to -submit other tasks immediately. Therefore it provides a simple way to throttle the -incoming load while maintaining the limits of the thread pool and queue. Typically this -allows the executor to "catch up" on the tasks it is handling and thereby frees up some -capacity on the queue, in the pool, or both. Any of these options can be chosen from an -enumeration of values available for the 'rejection-policy' attribute on the 'executor' +forces the thread that is calling the submit method to run the task itself. +The idea is that such a caller is busy while running that task and not able to +submit other tasks immediately. Therefore, it provides a simple way to throttle the +incoming load while maintaining the limits of the thread pool and queue. Typically, this +allows the executor to "`catch up`" on the tasks it is handling and thereby frees up some +capacity on the queue, in the pool, or both. You can choose any of these options from an +enumeration of values available for the `rejection-policy` attribute on the `executor` element. +The following example shows an `executor` element with a number of attributes to specify +various behaviors: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6510,13 +6930,16 @@ element. queue-capacity="100" rejection-policy="CALLER_RUNS"/> ---- +==== Finally, the `keep-alive` setting determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess -threads will get terminated. A time value of zero will cause excess threads to terminate +threads get terminated. A time value of zero causes excess threads to terminate immediately after executing a task without remaining follow-up work in the task queue. +The following example sets the `keep-alive` value to two minutes: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6525,18 +6948,21 @@ immediately after executing a task without remaining follow-up work in the task pool-size="5-25" keep-alive="120"/> ---- +==== + [[scheduling-task-namespace-scheduled-tasks]] -==== The 'scheduled-tasks' element +==== The 'scheduled-tasks' Element The most powerful feature of Spring's task namespace is the support for configuring tasks to be scheduled within a Spring Application Context. This follows an approach -similar to other "method-invokers" in Spring, such as that provided by the JMS namespace -for configuring Message-driven POJOs. Basically a "ref" attribute can point to any -Spring-managed object, and the "method" attribute provides the name of a method to be -invoked on that object. Here is a simple example. +similar to other "`method-invokers`" in Spring, such as that provided by the JMS namespace +for configuring message-driven POJOs. Basically, a `ref` attribute can point to any +Spring-managed object, and the `method` attribute provides the name of a method to be +invoked on that object. The following listing shows a simple example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6546,17 +6972,19 @@ invoked on that object. Here is a simple example. ---- +==== -As you can see, the scheduler is referenced by the outer element, and each individual +The scheduler is referenced by the outer element, and each individual task includes the configuration of its trigger metadata. In the preceding example, that metadata defines a periodic trigger with a fixed delay indicating the number of milliseconds to wait after each task execution has completed. Another option is -'fixed-rate', indicating how often the method should be executed regardless of how long -any previous execution takes. Additionally, for both fixed-delay and fixed-rate tasks an -'initial-delay' parameter may be specified indicating the number of milliseconds to wait -before the first execution of the method. For more control, a "cron" attribute may be -provided instead. Here is an example demonstrating these other options. +`fixed-rate`, indicating how often the method should be executed regardless of how long +any previous execution takes. Additionally, for both `fixed-delay` and `fixed-rate` tasks, you can specify an +'initial-delay' parameter, indicating the number of milliseconds to wait +before the first execution of the method. For more control, you can instead provide a `cron` attribute. +The following example shows these other options: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -6568,25 +6996,28 @@ provided instead. Here is an example demonstrating these other options. ---- +==== [[scheduling-quartz]] === Using the Quartz Scheduler -Quartz uses `Trigger`, `Job` and `JobDetail` objects to realize scheduling of all kinds -of jobs. For the basic concepts behind Quartz, have a look at +Quartz uses `Trigger`, `Job`, and `JobDetail` objects to realize scheduling of all kinds +of jobs. For the basic concepts behind Quartz, see http://quartz-scheduler.org[]. For convenience purposes, Spring offers a couple of -classes that simplify the usage of Quartz within Spring-based applications. +classes that simplify using Quartz within Spring-based applications. + [[scheduling-quartz-jobdetail]] -==== Using the JobDetailFactoryBean +==== Using the `JobDetailFactoryBean` -Quartz `JobDetail` objects contain all information needed to run a job. Spring provides a -`JobDetailFactoryBean` which provides bean-style properties for XML configuration purposes. -Let's have a look at an example: +Quartz `JobDetail` objects contain all the information needed to run a job. Spring provides a +`JobDetailFactoryBean`, which provides bean-style properties for XML configuration purposes. +Consider the following example: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6599,14 +7030,16 @@ Let's have a look at an example: ---- +==== -The job detail configuration has all information it needs to run the job (`ExampleJob`). +The job detail configuration has all the information it needs to run the job (`ExampleJob`). The timeout is specified in the job data map. The job data map is available through the `JobExecutionContext` (passed to you at execution time), but the `JobDetail` also gets -its properties from the job data mapped to properties of the job instance. So in this -case, if the `ExampleJob` contains a bean property named `timeout`, the `JobDetail` -will have it applied automatically: +its properties from the job data mapped to properties of the job instance. So, in the following example, +the `ExampleJob` contains a bean property named `timeout`, and the `JobDetail` +has it applied automatically: +==== [source,java,indent=0] [subs="verbatim"] ---- @@ -6630,23 +7063,23 @@ will have it applied automatically: } ---- +==== -All additional properties from the job data map are of course available to you as well. +All additional properties from the job data map are available to you as well. -[NOTE] -==== -Using the `name` and `group` properties, you can modify the name and the group +NOTE: By using the `name` and `group` properties, you can modify the name and the group of the job, respectively. By default, the name of the job matches the bean name -of the `JobDetailFactoryBean` (in the example above, this is `exampleJob`). -==== +of the `JobDetailFactoryBean` (`exampleJob` in the preceding example above). + [[scheduling-quartz-method-invoking-job]] -==== Using the MethodInvokingJobDetailFactoryBean +==== Using the `MethodInvokingJobDetailFactoryBean` -Often you just need to invoke a method on a specific object. Using the -`MethodInvokingJobDetailFactoryBean` you can do exactly this: +Often you merely need to invoke a method on a specific object. By using the +`MethodInvokingJobDetailFactoryBean`, you can do exactly this, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6655,10 +7088,12 @@ Often you just need to invoke a method on a specific object. Using the ---- +==== -The above example will result in the `doIt` method being called on the -`exampleBusinessObject` method (see below): +The preceding example results in the `doIt` method being called on the +`exampleBusinessObject` method, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6677,19 +7112,21 @@ The above example will result in the `doIt` method being called on the ---- ---- +==== -Using the `MethodInvokingJobDetailFactoryBean`, you don't need to create one-line jobs -that just invoke a method, and you only need to create the actual business object and +By using the `MethodInvokingJobDetailFactoryBean`, you need not create one-line jobs +that merely invoke a method. You need only create the actual business object and wire up the detail object. By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering -with each other. If you specify two triggers for the same `JobDetail`, it might be -possible that before the first job has finished, the second one will start. If -`JobDetail` classes implement the `Stateful` interface, this won't happen. The second -job will not start before the first one has finished. To make jobs resulting from the -`MethodInvokingJobDetailFactoryBean` non-concurrent, set the `concurrent` flag to -`false`. +with each other. If you specify two triggers for the same `JobDetail`, it is +possible that, before the first job has finished, the second one starts. If +`JobDetail` classes implement the `Stateful` interface, this does not happen. The second +job does not start before the first one has finished. To make jobs resulting from the +`MethodInvokingJobDetailFactoryBean` be non-concurrent, set the `concurrent` flag to +`false`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6699,20 +7136,19 @@ job will not start before the first one has finished. To make jobs resulting fro ---- - -[NOTE] -==== -By default, jobs will run in a concurrent fashion. ==== +NOTE: By default, jobs will run in a concurrent fashion. + + [[scheduling-quartz-cron]] -==== Wiring up jobs using triggers and the SchedulerFactoryBean +==== Wiring up Jobs by Using Triggers and `SchedulerFactoryBean` -We've created job details and jobs. We've also reviewed the convenience bean that allows -you to invoke a method on a specific object. Of course, we still need to schedule the -jobs themselves. This is done using triggers and a `SchedulerFactoryBean`. Several -triggers are available within Quartz and Spring offers two Quartz `FactoryBean` +We have created job details and jobs. We have also reviewed the convenience bean that lets +you invoke a method on a specific object. Of course, we still need to schedule the +jobs themselves. This is done by using triggers and a `SchedulerFactoryBean`. Several +triggers are available within Quartz, and Spring offers two Quartz `FactoryBean` implementations with convenient defaults: `CronTriggerFactoryBean` and `SimpleTriggerFactoryBean`. @@ -6720,8 +7156,9 @@ Triggers need to be scheduled. Spring offers a `SchedulerFactoryBean` that expos triggers to be set as properties. `SchedulerFactoryBean` schedules the actual jobs with those triggers. -Find below a couple of examples: +The following listing uses both a `SimpleTriggerFactoryBean` and a `CronTriggerFactoryBean`: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -6740,11 +7177,13 @@ Find below a couple of examples: ---- +==== -Now we've set up two triggers, one running every 50 seconds with a starting delay of 10 -seconds and one every morning at 6 AM. To finalize everything, we need to set up the -`SchedulerFactoryBean`: +The preceding example sets up two triggers, one running every 50 seconds with a starting delay of 10 +seconds and one running every morning at 6 AM. To finalize everything, we need to set up the +`SchedulerFactoryBean`, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -6757,12 +7196,13 @@ seconds and one every morning at 6 AM. To finalize everything, we need to set up ---- +==== -More properties are available for the `SchedulerFactoryBean` for you to set, such as the -calendars used by the job details, properties to customize Quartz with, etc. Have a look -at the +More properties are available for the `SchedulerFactoryBean`, such as the +calendars used by the job details, properties to customize Quartz with, and otehrs. See +the {api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean` -javadocs] for more information. +Javadoc] for more information. @@ -6770,13 +7210,8 @@ javadocs] for more information. [[cache]] == Cache Abstraction - - -[[cache-introduction]] -=== Introduction - -Since version 3.1, Spring Framework provides support for transparently adding caching -into an existing Spring application. Similar to the <> +Since version 3.1, the Spring Framework provides support for transparently adding caching +to an existing Spring application. Similar to the <> support, the caching abstraction allows consistent use of various caching solutions with minimal impact on the code. @@ -6786,203 +7221,203 @@ support of <> and more customization options. [[cache-strategies]] -=== Understanding the cache abstraction +=== Understanding the Cache Abstraction .Cache vs Buffer **** -The terms "buffer" and "cache" tend to be used interchangeably; note however they -represent different things. A buffer is used traditionally as an intermediate temporary -store for data between a fast and a slow entity. As one party would have to __wait__ for -the other affecting performance, the buffer alleviates this by allowing entire blocks of +The terms, "`buffer`" and "`cache,`" tend to be used interchangeably. Note, however, that they +represent different things. Traditionally, a buffer is used as an intermediate temporary +store for data between a fast and a slow entity. As one party would has to wait for +the other (which affects performance), the buffer alleviates this by allowing entire blocks of data to move at once rather then in small chunks. The data is written and read only once -from the buffer. Furthermore, the buffers are __visible__ to at least one party which is +from the buffer. Furthermore, the buffers are visible to at least one party that is aware of it. -A cache on the other hand by definition is hidden and neither party is aware that -caching occurs.It as well improves performance but does that by allowing the same data -to be read multiple times in a fast fashion. +A cache, on the other hand, is, by definition, hidden, and neither party is aware that +caching occurs. It also improves performance but does so by letting the same data +be read multiple times in a fast fashion. -A further explanation of the differences between two can be found +You can find a further explanation of the differences between a buffer and a cache http://en.wikipedia.org/wiki/Cache_(computing)#The_difference_between_buffer_and_cache[here]. **** -At its core, the abstraction applies caching to Java methods, reducing thus the number +At its core, the cache abstraction applies caching to Java methods, thus reducing the number of executions based on the information available in the cache. That is, each time a -__targeted__ method is invoked, the abstraction will apply a caching behavior checking -whether the method has been already executed for the given arguments. If it has, then -the cached result is returned without having to execute the actual method; if it has -not, then method is executed, the result cached and returned to the user so that, the +targeted method is invoked, the abstraction applies a caching behavior that checks +whether the method has been already executed for the given arguments. If it has been executed, +the cached result is returned without having to execute the actual method. If the method has +not been executed, then it is executed, and the result is cached and returned to the user so that, the next time the method is invoked, the cached result is returned. This way, expensive -methods (whether CPU or IO bound) can be executed only once for a given set of +methods (whether CPU- or IO-bound) can be executed only once for a given set of parameters and the result reused without having to actually execute the method again. The caching logic is applied transparently without any interference to the invoker. -[IMPORTANT] -==== - -Obviously this approach works only for methods that are guaranteed to return the same -output (result) for a given input (or arguments) no matter how many times it is being -executed. -==== +IMPORTANT: This approach works only for methods that are guaranteed to return the same +output (result) for a given input (or arguments) no matter how many times it is executed. -Other cache-related operations are provided by the abstraction such as the ability -to update the content of the cache or remove one of all entries. These are useful if +The caching abstraction provides other cache-related operations, such as the ability +to update the content of the cache or to remove one or all entries. These are useful if the cache deals with data that can change during the course of the application. -Just like other services in the Spring Framework, the caching service is an -abstraction (not a cache implementation) and requires the use of an actual storage to -store the cache data - that is, the abstraction frees the developer from having to write -the caching logic but does not provide the actual stores. This abstraction is +As with other services in the Spring Framework, the caching service is an +abstraction (not a cache implementation) and requires the use of actual storage to +store the cache data -- that is, the abstraction frees you from having to write +the caching logic but does not provide the actual data store. This abstraction is materialized by the `org.springframework.cache.Cache` and `org.springframework.cache.CacheManager` interfaces. -There are <> of that abstraction -available out of the box: JDK `java.util.concurrent.ConcurrentMap` based caches, +Spring provides <> of that abstraction: +JDK `java.util.concurrent.ConcurrentMap` based caches, http://ehcache.org/[Ehcache 2.x], Gemfire cache, -https://github.com/ben-manes/caffeine/wiki[Caffeine] and JSR-107 compliant -caches (e.g. Ehcache 3.x). See <> for more information on plugging in -other cache stores/providers. +https://github.com/ben-manes/caffeine/wiki[Caffeine], and JSR-107 compliant +caches (such as Ehcache 3.x). See <> for more information on plugging in +other cache stores and providers. -[IMPORTANT] -==== -The caching abstraction has no special handling of multi-threaded and multi-process -environments as such features are handled by the cache implementation. . -==== +IMPORTANT: The caching abstraction has no special handling for multi-threaded and multi-process +environments, as such features are handled by the cache implementation. . -If you have a multi-process environment (i.e. an application deployed on several nodes), -you will need to configure your cache provider accordingly. Depending on your use cases, -a copy of the same data on several nodes may be enough but if you change the data during +If you have a multi-process environment (that is, an application deployed on several nodes), +you need to configure your cache provider accordingly. Depending on your use cases, +a copy of the same data on several nodes can be enough. However, if you change the data during the course of the application, you may need to enable other propagation mechanisms. Caching a particular item is a direct equivalent of the typical get-if-not-found-then- -proceed-and-put-eventually code blocks found with programmatic cache interaction: no locks -are applied and several threads may try to load the same item concurrently. The same applies -to eviction: if several threads are trying to update or evict data concurrently, you may -use stale data. Certain cache providers offer advanced features in that area, refer to -the documentation of the cache provider that you are using for more details. +proceed-and-put-eventually code blocks found with programmatic cache interaction. No locks +are applied, and several threads may try to load the same item concurrently. The same applies +to eviction. If several threads are trying to update or evict data concurrently, you may +use stale data. Certain cache providers offer advanced features in that area. See +the documentation of your cache provider for more details. -To use the cache abstraction, the developer needs to take care of two aspects: +To use the cache abstraction, you need to take care of two aspects: -* caching declaration - identify the methods that need to be cached and their policy -* cache configuration - the backing cache where the data is stored and read from +* Caching declaration: Identify the methods that need to be cached and their policy. +* Cache configuration: The backing cache where the data is stored and from which it is read. [[cache-annotations]] -=== Declarative annotation-based caching +=== Declarative Annotation-based Caching -For caching declaration, the abstraction provides a set of Java annotations: +For caching declaration, Spring's caching abstraction provides a set of Java annotations: -* `@Cacheable` triggers cache population -* `@CacheEvict` triggers cache eviction -* `@CachePut` updates the cache without interfering with the method execution -* `@Caching` regroups multiple cache operations to be applied on a method -* `@CacheConfig` shares some common cache-related settings at class-level +* `@Cacheable`: Triggers cache population. +* `@CacheEvict`: Triggers cache eviction. +* `@CachePut`: Updates the cache without interfering with the method execution. +* `@Caching`: Regroups multiple cache operations to be applied on a method. +* `@CacheConfig`: Shares some common cache-related settings at class-level. -Let us take a closer look at each annotation: [[cache-annotations-cacheable]] -==== @Cacheable annotation +==== The `@Cacheable` Annotation -As the name implies, `@Cacheable` is used to demarcate methods that are cacheable - that -is, methods for whom the result is stored into the cache so on subsequent invocations +As the name implies, you can use `@Cacheable` to demarcate methods that are cacheable -- that +is, methods for which the result is stored in the cache so that, on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name -of the cache associated with the annotated method: +of the cache associated with the annotated method, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable("books") public Book findBook(ISBN isbn) {...} ---- +==== -In the snippet above, the method `findBook` is associated with the cache named `books`. +In the preceding snippet, the `findBook` method is associated with the cache named `books`. Each time the method is called, the cache is checked to see whether the invocation has -been already executed and does not have to be repeated. While in most cases, only one -cache is declared, the annotation allows multiple names to be specified so that more -than one cache are being used. In this case, each of the caches will be checked before -executing the method - if at least one cache is hit, then the associated value will be -returned: +already been executed and does not have to be repeated. While in most cases, only one +cache is declared, the annotation lets multiple names be specified so that more +than one cache is being used. In this case, each of the caches is checked before +executing the method -- if at least one cache is hit, the associated value is +returned. -[NOTE] -==== -All the other caches that do not contain the value will be updated as well even though +NOTE: All the other caches that do not contain the value are also updated, even though the cached method was not actually executed. -==== +The following example uses `@Cacheable` on the `findBook` method: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable({"books", "isbns"}) public Book findBook(ISBN isbn) {...} ---- +==== + + [[cache-annotations-cacheable-default-key]] ===== Default Key Generation Since caches are essentially key-value stores, each invocation of a cached method needs -to be translated into a suitable key for cache access. Out of the box, the caching +to be translated into a suitable key for cache access. The caching abstraction uses a simple `KeyGenerator` based on the following algorithm: * If no params are given, return `SimpleKey.EMPTY`. * If only one param is given, return that instance. -* If more the one param is given, return a `SimpleKey` containing all parameters. +* If more the one param is given, return a `SimpleKey` that contains all parameters. -This approach works well for most use-cases; As long as parameters have __natural keys__ -and implement valid `hashCode()` and `equals()` methods. If that is not the case then the -strategy needs to be changed. +This approach works well for most use-cases, as long as parameters have natural keys +and implement valid `hashCode()` and `equals()` methods. If that is not the case, you need to change the +strategy. -To provide a different __default__ key generator, one needs to implement the +To provide a different default key generator, you need to implement the `org.springframework.cache.interceptor.KeyGenerator` interface. - [NOTE] ==== The default key generation strategy changed with the release of Spring 4.0. Earlier versions of Spring used a key generation strategy that, for multiple key parameters, -only considered the `hashCode()` of parameters and not `equals()`; this could cause +considered only the `hashCode()` of parameters and not `equals()`. This could cause unexpected key collisions (see https://jira.spring.io/browse/SPR-10237[SPR-10237] -for background). The new 'SimpleKeyGenerator' uses a compound key for such scenarios. +for background). The new `SimpleKeyGenerator` uses a compound key for such scenarios. If you want to keep using the previous key strategy, you can configure the deprecated `org.springframework.cache.interceptor.DefaultKeyGenerator` class or create a custom -hash-based 'KeyGenerator' implementation. +hash-based `KeyGenerator` implementation. ==== + + [[cache-annotations-cacheable-key]] ===== Custom Key Generation Declaration -Since caching is generic, it is quite likely the target methods have various signatures -that cannot be simply mapped on top of the cache structure. This tends to become obvious +Since caching is generic, the target methods are quite likely to have various signatures +that cannot be readily mapped on top of the cache structure. This tends to become obvious when the target method has multiple arguments out of which only some are suitable for -caching (while the rest are used only by the method logic). For example: +caching (while the rest are used only by the method logic). Consider the following example: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable("books") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- +==== At first glance, while the two `boolean` arguments influence the way the book is found, -they are no use for the cache. Further more what if only one of the two is important +they are no use for the cache. Furthermore, what if only one of the two is important while the other is not? -For such cases, the `@Cacheable` annotation allows the user to specify how the key is -generated through its `key` attribute. The developer can use <> to -pick the arguments of interest (or their nested properties), perform operations or even +For such cases, the `@Cacheable` annotation lets you specify how the key is +generated through its `key` attribute. You can use <> to +pick the arguments of interest (or their nested properties), perform operations, or even invoke arbitrary methods without having to write any code or implement any interface. This is the recommended approach over the -<> since methods tend to be -quite different in signatures as the code base grows; while the default strategy might -work for some methods, it rarely does for all methods. +<>, since methods tend to be +quite different in signatures as the code base grows. While the default strategy might +work for some methods, it rarely works for all methods. -Below are some examples of various SpEL declarations - if you are not familiar with it, -do yourself a favor and read <>: +The following examples ise various SpEL declarations (if you are not familiar with SpEL, +do yourself a favor and read <>): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -6995,156 +7430,180 @@ do yourself a favor and read < @Cacheable(cacheNames="books", **key="T(someType).hash(#isbn)"**) public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- +==== -The snippets above show how easy it is to select a certain argument, one of its -properties or even an arbitrary (static) method. +The preceding snippets show how easy it is to select a certain argument, one of its +properties, or even an arbitrary (static) method. -If the algorithm responsible to generate the key is too specific or if it needs -to be shared, you may define a custom `keyGenerator` on the operation. To do -this, specify the name of the `KeyGenerator` bean implementation to use: +If the algorithm responsible for generating the key is too specific or if it needs +to be shared, you can define a custom `keyGenerator` on the operation. To do +so, specify the name of the `KeyGenerator` bean implementation to use, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable(cacheNames="books", **keyGenerator="myKeyGenerator"**) public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- - -[NOTE] -==== -The `key` and `keyGenerator` parameters are mutually exclusive and an operation -specifying both will result in an exception. ==== +NOTE: The `key` and `keyGenerator` parameters are mutually exclusive and an operation +that specifies both results in an exception. + + + [[cache-annotations-cacheable-default-cache-resolver]] ===== Default Cache Resolution -Out of the box, the caching abstraction uses a simple `CacheResolver` that -retrieves the cache(s) defined at the operation level using the configured +The caching abstraction uses a simple `CacheResolver` that +retrieves the caches defined at the operation level by using the configured `CacheManager`. -To provide a different __default__ cache resolver, one needs to implement the +To provide a different default cache resolver, you need to implement the `org.springframework.cache.interceptor.CacheResolver` interface. + + [[cache-annotations-cacheable-cache-resolver]] -===== Custom cache resolution +===== Custom Cache Resolution -The default cache resolution fits well for applications working with a -single `CacheManager` and with no complex cache resolution requirements. +The default cache resolution fits well for applications that work with a +single `CacheManager` and have no complex cache resolution requirements. -For applications working with several cache managers, it is possible -to set the `cacheManager` to use per operation: +For applications that work with several cache managers, you can +set the `cacheManager` to use for each operation, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Cacheable(cacheNames="books", **cacheManager="anotherCacheManager"**) + @Cacheable(cacheNames="books", cacheManager="anotherCacheManager") <1> public Book findBook(ISBN isbn) {...} ---- +<1> Specifying `anotherCacheManager`. +==== -It is also possible to replace the `CacheResolver` entirely in a similar -fashion as for <>. The -resolution is requested for every cache operation, giving a chance to -the implementation to actually resolve the cache(s) to use based on -runtime arguments: +You can also replace the `CacheResolver` entirely in a fashion similar to that of +replacing <>. The +resolution is requested for every cache operation, letting +the implementation actually resolve the caches to use based on +runtime arguments. The following example shows how to specify a `CacheResolver`: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Cacheable(**cacheResolver="runtimeCacheResolver"**) + @Cacheable(cacheResolver="runtimeCacheResolver") <1> public Book findBook(ISBN isbn) {...} ---- +<1> Specifying the `CacheResolver`. +==== [NOTE] ==== Since Spring 4.1, the `value` attribute of the cache annotations are no longer -mandatory since this particular information can be provided by the `CacheResolver` +mandatory, since this particular information can be provided by the `CacheResolver` regardless of the content of the annotation. Similarly to `key` and `keyGenerator`, the `cacheManager` and `cacheResolver` -parameters are mutually exclusive and an operation specifying both will -result in an exception as a custom `CacheManager` will be ignored by the +parameters are mutually exclusive, and an operation specifying both +results in an exception. as a custom `CacheManager` is ignored by the `CacheResolver` implementation. This is probably not what you expect. ==== + + [[cache-annotations-cacheable-synchronized]] -===== Synchronized caching +===== Synchronized Caching In a multi-threaded environment, certain operations might be concurrently invoked for the same argument (typically on startup). By default, the cache abstraction does not -lock anything and the same value may be computed several times, defeating the purpose +lock anything, and the same value may be computed several times, defeating the purpose of caching. -For those particular cases, the `sync` attribute can be used to instruct the underlying -cache provider to _lock_ the cache entry while the value is being computed. As a result, -only one thread will be busy computing the value while the others are blocked until the -entry is updated in the cache. +For those particular cases, you can use the `sync` attribute to instruct the underlying +cache provider to lock the cache entry while the value is being computed. As a result, +only one thread is busy computing the value, while the others are blocked until the +entry is updated in the cache. The following example shows how to use the `sync` attribute: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Cacheable(cacheNames="foos", **sync=true**) + @Cacheable(cacheNames="foos", sync=true) <1> public Foo executeExpensiveOperation(String id) {...} ---- - -[NOTE] +<1> Using the `sync` attribute. ==== -This is an optional feature and your favorite cache library may not support it. All -`CacheManager` implementations provided by the core framework support it. Check the + +NOTE: This is an optional feature, and your favorite cache library may not support it. All +`CacheManager` implementations provided by the core framework support it. See the documentation of your cache provider for more details. -==== + + [[cache-annotations-cacheable-condition]] -===== Conditional caching +===== Conditional Caching Sometimes, a method might not be suitable for caching all the time (for example, it might depend on the given arguments). The cache annotations support such functionality -through the `condition` parameter which takes a `SpEL` expression that is evaluated to -either `true` or `false`. If `true`, the method is cached - if not, it behaves as if the -method is not cached, that is executed every time no matter what values are in the cache -or what arguments are used. A quick example - the following method will be cached only +through the `condition` parameter, which takes a `SpEL` expression that is evaluated to +either `true` or `false`. If `true`, the method is cached. If not, it behaves as if the +method is not cached (that is, the method is executed every time no matter what values are in the cache +or what arguments are used). For example, the following method is cached only if the argument `name` has a length shorter than 32: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Cacheable(cacheNames="book", **condition="#name.length() < 32"**) + @Cacheable(cacheNames="book", condition="#name.length() < 32") <1> public Book findBook(String name) ---- +<1> Setting a condition on `@Cacheable`. +==== -In addition the `condition` parameter, the `unless` parameter can be used to veto the +In addition to the `condition` parameter, you can use the `unless` parameter to veto the adding of a value to the cache. Unlike `condition`, `unless` expressions are evaluated -__after__ the method has been called. Expanding on the previous example - perhaps we -only want to cache paperback books: +after the method has been called. To expand on the previous example, perhaps we +only want to cache paperback books, as the following example does: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Cacheable(cacheNames="book", condition="#name.length() < 32", **unless="#result.hardback"**) + @Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback") <1> public Book findBook(String name) ---- +<1> Using the `unless` attribute to block hardbacks. +==== -The cache abstraction supports `java.util.Optional`, using its content as cached value -only if it present. `#result` always refers to the business entity and never on a -supported wrapper so the previous example can be rewritten as follows: +The cache abstraction supports `java.util.Optional`, using its content as the cached value +only if it is present. `#result` always refers to the business entity and never a +supported wrapper, so the previous example can be rewritten as follows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable(cacheNames="book", condition="#name.length() < 32", **unless="#result?.hardback"**) public Optional findBook(String name) ---- +==== Note that `result` still refers to `Book` and not `Optional`. As it might be `null`, we should use the safe navigation operator. + + [[cache-spel-context]] -===== Available caching SpEL evaluation context +===== Available Caching SpEL Evaluation Context -Each `SpEL` expression evaluates again a dedicated -<>. In addition to the build in parameters, the -framework provides dedicated caching related metadata such as the argument names. The -next table lists the items made available to the context so one can use them for key and +Each `SpEL` expression evaluates against a dedicated +<>. In addition to the built-in parameters, the +framework provides dedicated caching-related metadata, such as the argument names. The +following table describes the items made available to the context so that you can use them for key and conditional computations: [[cache-spel-context-tbl]] @@ -7152,61 +7611,62 @@ conditional computations: |=== | Name| Location| Description| Example -| methodName -| root object +| `methodName` +| Root object | The name of the method being invoked | `#root.methodName` -| method -| root object +| `method` +| Root object | The method being invoked | `#root.method.name` -| target -| root object +| `target` +| Root object | The target object being invoked | `#root.target` -| targetClass -| root object +| `targetClass` +| Root object | The class of the target being invoked | `#root.targetClass` -| args -| root object +| `args` +| Root object | The arguments (as array) used for invoking the target | `#root.args[0]` -| caches -| root object +| `caches` +| Root object | Collection of caches against which the current method is executed | `#root.caches[0].name` -| __argument name__ -| evaluation context -| Name of any of the method arguments. If for some reason the names are not available - (e.g. no debug information), the argument names are also available under the `#a<#arg>` - where __#arg__ stands for the argument index (starting from 0). -| `#iban` or `#a0` (one can also use `#p0` or `#p<#arg>` notation as an alias). +| Argument name +| Evaluation context +| Name of any of the method arguments. If the names are not available + (prehaps due to having no debug information), the argument names are also available under the `#a<#arg>` + where `#arg` stands for the argument index (starting from `0`). +| `#iban` or `#a0` (you can also use `#p0` or `#p<#arg>` notation as an alias). -| result -| evaluation context +| `result` +| Evaluation context | The result of the method call (the value to be cached). Only available in `unless` expressions, `cache put` expressions (to compute the `key`), or `cache evict` - expressions (when `beforeInvocation` is `false`). For supported wrappers such as - `Optional`, `#result` refers to the actual object, not the wrapper. + expressions (when `beforeInvocation` is `false`). For supported wrappers (such as + `Optional`), `#result` refers to the actual object, not the wrapper. | `#result` |=== + [[cache-annotations-put]] -==== @CachePut annotation +==== The `@CachePut` Annotation -For cases where the cache needs to be updated without interfering with the method -execution, one can use the `@CachePut` annotation. That is, the method will always be -executed and its result placed into the cache (according to the `@CachePut` options). It +When the cache needs to be updated without interfering with the method +execution, you can use the `@CachePut` annotation. That is, the method is always +executed and its result is placed into the cache (according to the `@CachePut` options). It supports the same options as `@Cacheable` and should be used for cache population rather -than method flow optimization: +than method flow optimization. The following example uses the `@CachePut` annotation: [source,java,indent=0] [subs="verbatim,quotes"] @@ -7215,111 +7675,122 @@ than method flow optimization: public Book updateBook(ISBN isbn, BookDescriptor descriptor) ---- -[IMPORTANT] -==== -Note that using `@CachePut` and `@Cacheable` annotations on the same method is generally +IMPORTANT: Using `@CachePut` and `@Cacheable` annotations on the same method is generally strongly discouraged because they have different behaviors. While the latter causes the method execution to be skipped by using the cache, the former forces the execution in -order to execute a cache update. This leads to unexpected behavior and with the exception of +order to execute a cache update. This leads to unexpected behavior and, with the exception of specific corner-cases (such as annotations having conditions that exclude them from each -other), such declaration should be avoided. Note also that such condition should not rely -on the result object (i.e. the `#result` variable) as these are validated upfront to confirm +other), such declarations should be avoided. Note also that such conditions should not rely +on the result object (that is, the `#result` variable), as these are validated up-front to confirm the exclusion. -==== + [[cache-annotations-evict]] -==== @CacheEvict annotation +==== The `@CacheEvict` annotation The cache abstraction allows not just population of a cache store but also eviction. -This process is useful for removing stale or unused data from the cache. Opposed to -`@Cacheable`, annotation `@CacheEvict` demarcates methods that perform cache -__eviction__, that is methods that act as triggers for removing data from the cache. -Just like its sibling, `@CacheEvict` requires specifying one (or multiple) caches +This process is useful for removing stale or unused data from the cache. As opposed to +`@Cacheable`, `@CacheEvict` demarcates methods that perform cache +eviction (that is, methods that act as triggers for removing data from the cache). +Similarly to its sibling, `@CacheEvict` requires specifying one or more caches that are affected by the action, allows a custom cache and key resolution or a -condition to be specified but in addition, features an extra parameter -`allEntries` which indicates whether a cache-wide eviction needs to be performed -rather then just an entry one (based on the key): +condition to be specified, and features an extra parameter +(`allEntries`) that indicates whether a cache-wide eviction needs to be performed +rather then just an entry eviction (based on the key). The following example evicts +all entries from the `books` cache: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @CacheEvict(cacheNames="books", **allEntries=true**) + @CacheEvict(cacheNames="books", allEntries=true) <1> public void loadBooks(InputStream batch) ---- +<1> Using the `allEntries` attribute to evict all entries from the cache. +==== -This option comes in handy when an entire cache region needs to be cleared out - rather -then evicting each entry (which would take a long time since it is inefficient), all the -entries are removed in one operation as shown above. Note that the framework will ignore -any key specified in this scenario as it does not apply (the entire cache is evicted not -just one entry). +This option comes in handy when an entire cache region needs to be cleared out. Rather +then evicting each entry (which would take a long time, since it is inefficient), all the +entries are removed in one operation, as the preceding example shows. Note that the framework ignores +any key specified in this scenario as it does not apply (the entire cache is evicted, not +only one entry). -One can also indicate whether the eviction should occur after (the default) or before -the method executes through the `beforeInvocation` attribute. The former provides the -same semantics as the rest of the annotations - once the method completes successfully, -an action (in this case eviction) on the cache is executed. If the method does not +You can also indicate whether the eviction should occur after (the default) or before +the method executes by using the `beforeInvocation` attribute. The former provides the +same semantics as the rest of the annotations: Once the method completes successfully, +an action (in this case, eviction) on the cache is executed. If the method does not execute (as it might be cached) or an exception is thrown, the eviction does not occur. -The latter ( `beforeInvocation=true`) causes the eviction to occur always, before the -method is invoked - this is useful in cases where the eviction does not need to be tied +The latter (`beforeInvocation=true`) causes the eviction to always occur before the +method is invoked. This is useful in cases where the eviction does not need to be tied to the method outcome. -It is important to note that void methods can be used with `@CacheEvict` - as the -methods act as triggers, the return values are ignored (as they don't interact with the -cache) - this is not the case with `@Cacheable` which adds/updates data into the cache -and thus requires a result. +Note that `void` methods can be used with `@CacheEvict` - as the +methods act as a trigger, the return values are ignored (as they do nt interact with the +cache). This is not the case with `@Cacheable` which adds or updates data into the cache +and, thus, requires a result. + [[cache-annotations-caching]] -==== @Caching annotation +==== The `@Caching` Annotation -There are cases when multiple annotations of the same type, such as `@CacheEvict` or -`@CachePut` need to be specified, for example because the condition or the key -expression is different between different caches. `@Caching` allows multiple nested -`@Cacheable`, `@CachePut` and `@CacheEvict` to be used on the same method: +Sometimes, multiple annotations of the same type (such as `@CacheEvict` or +`@CachePut`) need to be specified -- for example, because the condition or the key +expression is different between different caches. `@Caching` lets multiple nested +`@Cacheable`, `@CachePut`, and `@CacheEvict` annotations be used on the same method. +The following example uses two `@CacheEvict` annotations: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") }) public Book importBooks(String deposit, Date date) ---- +==== + [[cache-annotations-config]] -==== @CacheConfig annotation +==== The `@CacheConfig` annotation -So far we have seen that caching operations offered many customization options and -these can be set on an operation basis. However, some of the customization options +So far, we have seen that caching operations offer many customization options and that +you can set these options for each operation. However, some of the customization options can be tedious to configure if they apply to all operations of the class. For instance, specifying the name of the cache to use for every cache operation of the -class could be replaced by a single class-level definition. This is where `@CacheConfig` -comes into play. +class can be replaced by a single class-level definition. This is where `@CacheConfig` +comes into play. The following examples uses `@CacheConfig` to set the name of the cache: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - **@CacheConfig("books")** + @CacheConfig("books") <1> public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...} } ---- +<1> Using `@CacheConfig` to set the name of the cache. +==== -`@CacheConfig` is a class-level annotation that allows to share the cache names, the custom -`KeyGenerator`, the custom `CacheManager` and finally the custom `CacheResolver`. Placing +`@CacheConfig` is a class-level annotation that allows sharing the cache names, the custom +`KeyGenerator`, the custom `CacheManager`, and the custom `CacheResolver`. Placing this annotation on the class does not turn on any caching operation. -An operation-level customization will always override a customization set on `@CacheConfig`. This -gives therefore three levels of customizations per cache operation: +An operation-level customization always overrides a customization set on `@CacheConfig`. Therefore, this +gives three levels of customizations for each cache operation: + +* Globally configured, available for `CacheManager`, `KeyGenerator`. +* At the class level, using `@CacheConfig`. +* At the operation level. -* Globally configured, available for `CacheManager`, `KeyGenerator` -* At class level, using `@CacheConfig` -* At the operation level [[cache-annotation-enable]] -==== Enable caching annotations +==== Enabling Caching Annotations It is important to note that even though declaring the cache annotations does not automatically trigger their actions - like many things in Spring, the feature has to be @@ -7339,8 +7810,9 @@ To enable caching annotations add the annotation `@EnableCaching` to one of your } ---- -Alternatively for XML configuration use the `cache:annotation-driven` element: +Alternatively, for XML configuration you can use the `cache:annotation-driven` element: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -7354,26 +7826,21 @@ Alternatively for XML configuration use the `cache:annotation-driven` element: ---- +==== -Both the `cache:annotation-driven` element and `@EnableCaching` annotation allow various -options to be specified that influence the way the caching behavior is added to the +Both the `cache:annotation-driven` element and the `@EnableCaching` annotation let you specify various +options that influence the way the caching behavior is added to the application through AOP. The configuration is intentionally similar with that of -<>: +<>. -[NOTE] -==== -The default advice mode for processing caching annotations is "proxy" which allows -for interception of calls through the proxy only; local calls within the same class +NOTE: The default advice mode for processing caching annotations is `proxy`, which allows +for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider -switching to "aspectj" mode in combination with compile-time or load-time weaving. -==== +switching to `aspectj` mode in combination with compile-time or load-time weaving. -[NOTE] -==== -Advanced customizations using Java config require to implement `CachingConfigurer`: -Please refer to {api-spring-framework}/cache/annotation/CachingConfigurer.html[the -javadoc for more details]. -==== +NOTE: For more detail about advanced customizations (using Java configuration) that are required to implement `CachingConfigurer`, +see {api-spring-framework}/cache/annotation/CachingConfigurer.html[the +Javadoc]. [[cache-annotation-driven-settings]] .Cache annotation settings @@ -7382,51 +7849,51 @@ javadoc for more details]. | XML Attribute | Annotation Attribute | Default | Description | `cache-manager` -| N/A (See `CachingConfigurer` javadocs) -| cacheManager -| Name of cache manager to use. A default `CacheResolver` will be initialized behind - the scenes with this cache manager (or `cacheManager`if not set). For more +| N/A (See {api-spring-framework}/cache/annotation/CachingConfigurer.html[the `CachingConfigurer` Javadoc]) +| `cacheManager` +| The name of the cache manager to use. A default `CacheResolver` is initialized behind + the scenes with this cache manager (or `cacheManager` if not set). For more fine-grained management of the cache resolution, consider setting the 'cache-resolver' attribute. | `cache-resolver` -| N/A (See `CachingConfigurer` javadocs) +| N/A (See {api-spring-framework}/cache/annotation/CachingConfigurer.html[the`CachingConfigurer` Javadoc]) | A `SimpleCacheResolver` using the configured `cacheManager`. | The bean name of the CacheResolver that is to be used to resolve the backing caches. - This attribute is not required, and only needs to be specified as an alternative to + This attribute is not required and needs to be specified only as an alternative to the 'cache-manager' attribute. | `key-generator` -| N/A (See `CachingConfigurer` javadocs) +| N/A (See {api-spring-framework}/cache/annotation/CachingConfigurer.html[the`CachingConfigurer` Javadoc]) | `SimpleKeyGenerator` | Name of the custom key generator to use. | `error-handler` -| N/A (See `CachingConfigurer` javadocs) +| N/A (See {api-spring-framework}/cache/annotation/CachingConfigurer.html[the`CachingConfigurer` Javadoc]) | `SimpleCacheErrorHandler` -| Name of the custom cache error handler to use. By default, any exception throw during - a cache related operations are thrown back at the client. +| The name of the custom cache error handler to use. By default, any exception thrown during + a cache related operation is thrown back at the client. | `mode` | `mode` -| proxy -| The default mode "proxy" processes annotated beans to be proxied using Spring's AOP - framework (following proxy semantics, as discussed above, applying to method calls - coming in through the proxy only). The alternative mode "aspectj" instead weaves the +| `proxy` +| The default mode (`proxy`) processes annotated beans to be proxied by using Spring's AOP + framework (following proxy semantics, as discussed earlier, applying to method calls + coming in through the proxy only). The alternative mode (`aspectj`) instead weaves the affected classes with Spring's AspectJ caching aspect, modifying the target class byte - code to apply to any kind of method call. AspectJ weaving requires spring-aspects.jar + code to apply to any kind of method call. AspectJ weaving requires `spring-aspects.jar` in the classpath as well as load-time weaving (or compile-time weaving) enabled. (See <> for details on how to set up load-time weaving.) | `proxy-target-class` | `proxyTargetClass` -| false +| `false` | Applies to proxy mode only. Controls what type of caching proxies are created for classes annotated with the `@Cacheable` or `@CacheEvict` annotations. If the - `proxy-target-class` attribute is set to `true`, then class-based proxies are created. - If `proxy-target-class` is `false` or if the attribute is omitted, then standard JDK - interface-based proxies are created. (See <> + `proxy-target-class` attribute is set to `true`, class-based proxies are created. + If `proxy-target-class` is `false` or if the attribute is omitted, standard JDK + interface-based proxies are created. (See <> for a detailed examination of the different proxy types.) | `order` @@ -7434,76 +7901,69 @@ javadoc for more details]. | Ordered.LOWEST_PRECEDENCE | Defines the order of the cache advice that is applied to beans annotated with `@Cacheable` or `@CacheEvict`. (For more information about the rules related to - ordering of AOP advice, see <>.) + ordering AOP advice, see <>.) No specified ordering means that the AOP subsystem determines the order of the advice. |=== -[NOTE] -==== -`` only looks for `@Cacheable/@CachePut/@CacheEvict/@Caching` -on beans in the same application context it is defined in. This means that, if you put +NOTE: `` looks for `@Cacheable/@CachePut/@CacheEvict/@Caching` +only on beans in the same application context in which it is defined. This means that, if you put `` in a `WebApplicationContext` for a `DispatcherServlet`, it -only checks for beans in your controllers, and not your services. +checks for beans only in your controllers, not your services. See <> for more information. -==== .Method visibility and cache annotations **** -When using proxies, you should apply the cache annotations only to methods with -__public__ visibility. If you do annotate protected, private or package-visible methods +When you use proxies, you should apply the cache annotations only to methods with +public visibility. If you do annotate protected, private, or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit -the configured caching settings. Consider the use of AspectJ (see below) if you need to -annotate non-public methods as it changes the bytecode itself. +the configured caching settings. Consider using AspectJ (see the rest of this section) if you need to +annotate non-public methods, as it changes the bytecode itself. **** -[TIP] -==== -Spring recommends that you only annotate concrete classes (and methods of concrete +TIP: Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the `@Cache{asterisk}` annotation, as opposed to annotating interfaces. You certainly can place the `@Cache{asterisk}` annotation on an interface (or an interface method), -but this works only as you would expect it to if you are using interface-based proxies. -The fact that Java annotations are __not inherited from interfaces__ means that if you -are using class-based proxies ( `proxy-target-class="true"`) or the weaving-based aspect -( `mode="aspectj"`), then the caching settings are not recognized by the proxying and -weaving infrastructure, and the object will not be wrapped in a caching proxy, which -would be decidedly __bad__. -==== +but this works only as you would expect it to if you use interface-based proxies. +The fact that Java annotations are not inherited from interfaces means that, if you +use class-based proxies (`proxy-target-class="true"`) or the weaving-based aspect +(`mode="aspectj"`), the caching settings are not recognized by the proxying and +weaving infrastructure, and the object is not wrapped in a caching proxy, which +would be decidedly bad. + +NOTE: In proxy mode (the default), only external method calls coming in through the +proxy are intercepted. This means that self-invocation (in effect, a method within the +target object that calls another method of the target object) does not lead to actual +caching at runtime even if the invoked method is marked with `@Cacheable`. Consider +using the `aspectj` mode in this case. Also, the proxy must be fully initialized to provide +the expected behavior, so you should not rely on this feature in your initialization +code (that is, `@PostConstruct`). -[NOTE] -==== -In proxy mode (which is the default), only external method calls coming in through the -proxy are intercepted. This means that self-invocation, in effect, a method within the -target object calling another method of the target object, will not lead to an actual -caching at runtime even if the invoked method is marked with `@Cacheable` - considering -using the aspectj mode in this case. Also, the proxy must be fully initialized to provide -the expected behaviour so you should not rely on this feature in your initialization -code, i.e. `@PostConstruct`. -==== [[cache-annotation-stereotype]] -==== Using custom annotations +==== Using Custom Annotations .Custom annotation and AspectJ **** -This feature only works out-of-the-box with the proxy-based approach but can be enabled -with a bit of extra effort using AspectJ. +This feature works only with the proxy-based approach but can be enabled +with a bit of extra effort by using AspectJ. The `spring-aspects` module defines an aspect for the standard annotations only. If you have defined your own annotations, you also need to define an aspect for those. Check `AnnotationCacheAspect` for an example. **** -The caching abstraction allows you to use your own annotations to identify what method -triggers cache population or eviction. This is quite handy as a template mechanism as it -eliminates the need to duplicate cache annotation declarations (especially useful if the -key or condition are specified) or if the foreign imports (`org.springframework`) are -not allowed in your code base. Similar to the rest of the -<> annotations, `@Cacheable`, `@CachePut`, -`@CacheEvict` and `@CacheConfig` can be used as <>, -that is annotations that can annotate other annotations. To wit, let us replace a common -`@Cacheable` declaration with our own, custom annotation: +The caching abstraction lets you use your own annotations to identify what method +triggers cache population or eviction. This is quite handy as a template mechanism, as it +eliminates the need to duplicate cache annotation declarations, which is especially useful if the +key or condition are specified or if the foreign imports (`org.springframework`) are +not allowed in your code base. Similarly to the rest of the +<> annotations, you can use `@Cacheable`, `@CachePut`, +`@CacheEvict`, and `@CacheConfig` as <> +(that is, annotations that can annotate other annotations). In the following example, we replace a common +`@Cacheable` declaration with our own custom annotation: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -7513,48 +7973,55 @@ that is annotations that can annotate other annotations. To wit, let us replace public @interface SlowService { } ---- +==== -Above, we have defined our own `SlowService` annotation which itself is annotated with -`@Cacheable` - now we can replace the following code: +In the preceding example, we have defined our own `SlowService` annotation, which itself is annotated with +`@Cacheable`. Now we can replace the following code: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @Cacheable(cacheNames="books", key="#isbn") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- +==== -with: +The following example shows the custom annotation with which we can replace the preceding +code: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @SlowService public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- +==== Even though `@SlowService` is not a Spring annotation, the container automatically picks -up its declaration at runtime and understands its meaning. Note that as mentioned -<>, the annotation-driven behavior needs to be enabled. +up its declaration at runtime and understands its meaning. Note that, as mentioned +<>, annotation-driven behavior needs to be enabled. [[cache-jsr-107]] -=== JCache (JSR-107) annotations +=== JCache (JSR-107) Annotations -Since the Spring Framework 4.1, the caching abstraction fully supports the JCache -standard annotations: these are `@CacheResult`, `@CachePut`, `@CacheRemove` and -`@CacheRemoveAll` as well as the `@CacheDefaults`, `@CacheKey` and `@CacheValue` -companions. These annotations can be used right the way without migrating your -cache store to JSR-107: the internal implementation uses Spring's caching abstraction +Since version 4.1, the caching abstraction fully supports the JCache +standard annotations: `@CacheResult`, `@CachePut`, `@CacheRemove`, and +`@CacheRemoveAll` as well as the `@CacheDefaults`, `@CacheKey`, and `@CacheValue` +companions. You can use these annotations without migrating your +cache store to JSR-107. The internal implementation uses Spring's caching abstraction and provides default `CacheResolver` and `KeyGenerator` implementations that are compliant with the specification. In other words, if you are already using Spring's caching abstraction, you can switch to these standard annotations without changing your cache storage (or configuration, for that matter). + [[cache-jsr-107-summary]] -==== Feature summary +==== Feature Summary For those who are familiar with Spring's caching annotations, the following table describes the main differences between the Spring annotations and the JSR-107 @@ -7573,13 +8040,13 @@ counterpart: | `@CachePut` | `@CachePut` | While Spring updates the cache with the result of the method invocation, JCache - requires to pass it as an argument that is annotated with `@CacheValue`. Due - to this difference, JCache allows to update the cache before or after the + requires that it be passed it as an argument that is annotated with `@CacheValue`. Due + to this difference, JCache allows updating the cache before or after the actual method invocation. | `@CacheEvict` | `@CacheRemove` -| Fairly similar. `@CacheRemove` supports a conditional evict in case the +| Fairly similar. `@CacheRemove` supports conditional eviction when the method invocation results in an exception. | `@CacheEvict(allEntries=true)` @@ -7588,40 +8055,41 @@ counterpart: | `@CacheConfig` | `@CacheDefaults` -| Allows to configure the same concepts, in a similar fashion. +| Lets you configure the same concepts, in a similar fashion. |=== -JCache has the notion of `javax.cache.annotation.CacheResolver` that is identical -to the Spring's `CacheResolver` interface, except that JCache only supports a single +JCache has the notion of `javax.cache.annotation.CacheResolver`, which is identical +to the Spring's `CacheResolver` interface, except that JCache supports only a single cache. By default, a simple implementation retrieves the cache to use based on -the name declared on the annotation. It should be noted that if no cache name -is specified on the annotation, a default is automatically generated, check the -javadoc of `@CacheResult#cacheName()` for more information. +the name declared on the annotation. It should be noted that, if no cache name +is specified on the annotation, a default is automatically generated. See the +Javadoc of `@CacheResult#cacheName()` for more information. `CacheResolver` instances are retrieved by a `CacheResolverFactory`. It is -possible to customize the factory per cache operation: +possible to customize the factory for each cache operation, as the following example shows: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- - @CacheResult(cacheNames="books", *cacheResolverFactory=MyCacheResolverFactory.class*) + @CacheResult(cacheNames="books", cacheResolverFactory=MyCacheResolverFactory.class) <1> public Book findBook(ISBN isbn) ---- - -[NOTE] +<1> Customizing the factory for this operation. ==== -For all referenced _classes_, Spring tries to locate a bean with the given type. If + +NOTE: For all referenced classes, Spring tries to locate a bean with the given type. If more than one match exists, a new instance is created and can use the regular -bean lifecycle callbacks such as dependency injection. -==== +bean lifecycle callbacks, such as dependency injection. Keys are generated by a `javax.cache.annotation.CacheKeyGenerator` that serves the same purpose as Spring's `KeyGenerator`. By default, all method arguments are taken -into account unless at least one parameter is annotated with `@CacheKey`. This is +into account, unless at least one parameter is annotated with `@CacheKey`. This is similar to Spring's <>. For instance these are identical operations, one using Spring's -abstraction and the other with JCache: +declaration>>. For instance, the following are identical operations, one using Spring's +abstraction and the other using JCache: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -7631,18 +8099,20 @@ abstraction and the other with JCache: @CacheResult(cacheName="books") public Book findBook(**@CacheKey** ISBN isbn, boolean checkWarehouse, boolean includeUsed) ---- +==== -The `CacheKeyResolver` to use can also be specified on the operation, in a similar -fashion as the `CacheResolverFactory`. +You can also specify the `CacheKeyResolver` on the operation, similar +to how you can specify the `CacheResolverFactory`. -JCache can manage exceptions thrown by annotated methods: this can prevent an update of -the cache but it can also cache the exception as an indicator of the failure instead of -calling the method again. Let's assume that `InvalidIsbnNotFoundException` is thrown if -the structure of the ISBN is invalid. This is a permanent failure, no book could ever be -retrieved with such parameter. The following caches the exception so that further calls -with the same, invalid ISBN, throws the cached exception directly instead of invoking -the method again. +JCache can manage exceptions thrown by annotated methods. This can prevent an update of +the cache, but it can also cache the exception as an indicator of the failure instead of +calling the method again. Assume that `InvalidIsbnNotFoundException` is thrown if +the structure of the ISBN is invalid. This is a permanent failure (no book could ever be +retrieved with such a parameter). The following caches the exception so that further calls +with the same, invalid, ISBN throw the cached exception directly instead of invoking +the method again: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -7650,35 +8120,34 @@ the method again. **cachedExceptions = InvalidIsbnNotFoundException.class**) public Book findBook(ISBN isbn) ---- +==== ==== Enabling JSR-107 support -Nothing specific needs to be done to enable the JSR-107 support alongside Spring's +You need do nothing specific to enable the JSR-107 support alongside Spring's declarative annotation support. Both `@EnableCaching` and the -`cache:annotation-driven` element will enable automatically the JCache support +`cache:annotation-driven` element automatically enable the JCache support if both the JSR-107 API and the `spring-context-support` module are present in the classpath. -[NOTE] -==== -Depending of your use case, the choice is basically yours. You can even mix -and match services using the JSR-107 API and others using Spring's own -annotations. Be aware however that if these services are impacting the same -caches, a consistent and identical key generation implementation should be used. -==== +NOTE: Depending on your use case, the choice is basically yours. You can even mix +and match services by using the JSR-107 API on some and using Spring's own +annotations on others. However, if these services impact the same +caches, you should use a consistent and identical key generation implementation. [[cache-declarative-xml]] -=== Declarative XML-based caching +=== Declarative XML-based Caching -If annotations are not an option (no access to the sources or no external code), one can -use XML for declarative caching. So instead of annotating the methods for caching, one -specifies the target method and the caching directives externally (similar to the +If annotations are not an option (perhaps due to having no access to the sources or no external code), you can +use XML for declarative caching. So, instead of annotating the methods for caching, you can +specify the target method and the caching directives externally (similar to the declarative transaction management <>). -The previous example can be translated into: +The example from the previous section can be translated into the following example: +==== [source,xml,indent=0] [subs="verbatim"] ---- @@ -7700,46 +8169,48 @@ The previous example can be translated into: ---- +==== -In the configuration above, the `bookService` is made cacheable. The caching semantics -to apply are encapsulated in the `cache:advice` definition which instructs method -`findBooks` to be used for putting data into the cache while method `loadBooks` for -evicting data. Both definitions are working against the `books` cache. +In the preceding configuration, the `bookService` is made cacheable. The caching semantics +to apply are encapsulated in the `cache:advice` definition, which causes the +`findBooks` method to be used for putting data into the cache and the `loadBooks` method for +evicting data. Both definitions work against the `books` cache. The `aop:config` definition applies the cache advice to the appropriate points in the program by using the AspectJ pointcut expression (more information is available in <>). -In the example above, all methods from the `BookService` are considered and -the cache advice applied to them. - -The declarative XML caching supports all of the annotation-based model so moving between -the two should be fairly easy - further more both can be used inside the same -application. The XML based approach does not touch the target code however it is -inherently more verbose; when dealing with classes with overloaded methods that are -targeted for caching, identifying the proper methods does take an extra effort since the -`method` argument is not a good discriminator - in these cases, the AspectJ pointcut can -be used to cherry pick the target methods and apply the appropriate caching -functionality. However through XML, it is easier to apply a package/group/interface-wide -caching (again due to the AspectJ pointcut) and to create template-like definitions (as -we did in the example above by defining the target cache through the `cache:definitions` +In the preceding example, all methods from the `BookService` are considered and +the cache advice is applied to them. + +The declarative XML caching supports all of the annotation-based model, so moving between +the two should be fairly easy. Furthermore, both can be used inside the same +application. The XML-based approach does not touch the target code. However, it is +inherently more verbose. When dealing with classes that have overloaded methods that are +targeted for caching, identifying the proper methods does take an extra effort, since the +`method` argument is not a good discriminator. In these cases, you can use the AspectJ pointcut +to cherry pick the target methods and apply the appropriate caching +functionality. However, through XML, it is easier to apply package or group or interface-wide +caching (again, due to the AspectJ pointcut) and to create template-like definitions (as +we did in the preceding example by defining the target cache through the `cache:definitions` `cache` attribute). [[cache-store-configuration]] -=== Configuring the cache storage +=== Configuring the Cache Storage + +The cache abstraction provides several storage integration options. To use +them, you need to declare an appropriate `CacheManager` (an entity that +controls and manages `Cache` instances and that can be used to retrieve these for storage). -Out of the box, the cache abstraction provides several storage integration. To use -them, one needs to simply declare an appropriate `CacheManager` - an entity that -controls and manages ``Cache``s and can be used to retrieve these for storage. [[cache-store-configuration-jdk]] -==== JDK ConcurrentMap-based Cache +==== JDK `ConcurrentMap`-based Cache The JDK-based `Cache` implementation resides under -`org.springframework.cache.concurrent` package. It allows one to use `ConcurrentHashMap` -as a backing `Cache` store. +`org.springframework.cache.concurrent` package. It lets you use `ConcurrentHashMap` +as a backing `Cache` store. The following example shows how to configure two caches: [source,xml,indent=0] [subs="verbatim,quotes"] @@ -7755,24 +8226,27 @@ as a backing `Cache` store. ---- -The snippet above uses the `SimpleCacheManager` to create a `CacheManager` for the two -nested `ConcurrentMapCache` instances named __default__ and __books__. Note that the +The preceding snippet uses the `SimpleCacheManager` to create a `CacheManager` for the two +nested `ConcurrentMapCache` instances named `default` and `books`. Note that the names are configured directly for each cache. As the cache is created by the application, it is bound to its lifecycle, making it -suitable for basic use cases, tests or simple applications. The cache scales well and is -very fast but it does not provide any management or persistence capabilities nor +suitable for basic use cases, tests, or simple applications. The cache scales well and is +very fast, but it does not provide any management, persistence capabilities, or eviction contracts. + [[cache-store-configuration-ehcache]] ==== Ehcache-based Cache NOTE: Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it. -The Ehcache 2.x implementation is located under `org.springframework.cache.ehcache` package. -Again, to use it, one simply needs to declare the appropriate `CacheManager`: +The Ehcache 2.x implementation is located in the `org.springframework.cache.ehcache` package. +Again, to use it, you need to declare the appropriate `CacheManager`. The following +example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -7783,31 +8257,36 @@ Again, to use it, one simply needs to declare the appropriate `CacheManager`: ---- +==== -This setup bootstraps the ehcache library inside Spring IoC (through the `ehcache` bean) which -is then wired into the dedicated `CacheManager` implementation. Note the entire +This setup bootstraps the ehcache library inside the Spring IoC (through the `ehcache` bean), which +is then wired into the dedicated `CacheManager` implementation. Note that the entire ehcache-specific configuration is read from `ehcache.xml`. + [[cache-store-configuration-caffeine]] ==== Caffeine Cache -Caffeine is a Java 8 rewrite of Guava's cache and its implementation is located under +Caffeine is a Java 8 rewrite of Guava's cache, and its implementation is located in the `org.springframework.cache.caffeine` package and provides access to several features of Caffeine. -Configuring a `CacheManager` that creates the cache on demand is straightforward: +The following example configures a `CacheManager` that creates the cache on demand: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- ---- +==== -It is also possible to provide the caches to use explicitly. In that case, only those -will be made available by the manager: +You can also provide the caches to use explicitly. In that case, only those +are made available by the manager. The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -7820,30 +8299,34 @@ will be made available by the manager: ---- +==== -The Caffeine `CacheManager` also supports customs `Caffeine` and `CacheLoader`. See +The Caffeine `CacheManager` also supports custom `Caffeine` and `CacheLoader`. See the https://github.com/ben-manes/caffeine/wiki[Caffeine documentation] for more information about those. + [[cache-store-configuration-gemfire]] ==== GemFire-based Cache -GemFire is a memory-oriented/disk-backed, elastically scalable, continuously available, +GemFire is a memory-oriented, disk-backed, elastically scalable, continuously available, active (with built-in pattern-based subscription notifications), globally replicated database and provides fully-featured edge caching. For further information on how to use -GemFire as a CacheManager (and more), please refer to the +GemFire as a `CacheManager` (and more), see the {doc-spring-gemfire}/html/[Spring Data GemFire reference documentation]. [[cache-store-configuration-jsr107]] ==== JSR-107 Cache -JSR-107 compliant caches can also be used by Spring's caching abstraction. The JCache -implementation is located under `org.springframework.cache.jcache` package. +Spring's caching abstraction can also use JSR-107-compliant caches. The JCache +implementation is located in the `org.springframework.cache.jcache` package. -Again, to use it, one simply needs to declare the appropriate `CacheManager`: +Again, to use it, you need to declare the appropriate `CacheManager`. The following +example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -7854,18 +8337,22 @@ Again, to use it, one simply needs to declare the appropriate `CacheManager`: ---- +==== + [[cache-store-configuration-noop]] -==== Dealing with caches without a backing store +==== Dealing with Caches without a Backing Store -Sometimes when switching environments or doing testing, one might have cache -declarations without an actual backing cache configured. As this is an invalid -configuration, at runtime an exception will be thrown since the caching infrastructure +Sometimes, when switching environments or doing testing, you might have cache +declarations without having an actual backing cache configured. As this is an invalid +configuration, an exception is thrown at runtime, since the caching infrastructure is unable to find a suitable store. In situations like this, rather then removing the -cache declarations (which can prove tedious), one can wire in a simple, dummy cache that -performs no caching - that is, forces the cached methods to be executed every time: +cache declarations (which can prove tedious), you can wire in a simple dummy cache that +performs no caching -- that is, it forces the cached methods to be executed every time. +The following example shows how to do so: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -7879,42 +8366,42 @@ performs no caching - that is, forces the cached methods to be executed every ti ---- +==== -The `CompositeCacheManager` above chains multiple ``CacheManager``s and additionally, -through the `fallbackToNoOpCache` flag, adds a __no op__ cache that for all the +The `CompositeCacheManager` in the preceding chains multiple `CacheManager` istancess and, +through the `fallbackToNoOpCache` flag, adds a no-op cache for all the definitions not handled by the configured cache managers. That is, every cache -definition not found in either `jdkCache` or `gemfireCache` (configured above) will be -handled by the no op cache, which will not store any information causing the target +definition not found in either `jdkCache` or `gemfireCache` (configured earlier in the example) is +handled by the no-op cache, which does not store any information, causing the target method to be executed every time. [[cache-plug]] -=== Plugging-in different back-end caches - -Clearly there are plenty of caching products out there that can be used as a backing -store. To plug them in, one needs to provide a `CacheManager` and `Cache` implementation -since unfortunately there is no available standard that we can use instead. This may -sound harder than it is since in practice, the classes tend to be simple -http://en.wikipedia.org/wiki/Adapter_pattern[adapter]s that map the caching abstraction -framework on top of the storage API as the `ehcache` classes can show. Most -`CacheManager` classes can use the classes in `org.springframework.cache.support` -package, such as `AbstractCacheManager` which takes care of the boiler-plate code -leaving only the actual __mapping__ to be completed. We hope that in time, the libraries +=== Plugging-in Different Back-end Caches + +Clearly, there are plenty of caching products out there that you can use as a backing +store. To plug them in, you need to provide a `CacheManager` and a `Cache` implementation, +since, unfortunately, there is no available standard that we can use instead. This may +sound harder than it is, since, in practice, the classes tend to be simple +http://en.wikipedia.org/wiki/Adapter_pattern[adapters] that map the caching abstraction +framework on top of the storage API, as the `ehcache` classes do. Most +`CacheManager` classes can use the classes in the `org.springframework.cache.support` +package, (such as `AbstractCacheManager`, which takes care of the boiler-plate code, +leaving only the actual mapping to be completed). We hope that, in time, the libraries that provide integration with Spring can fill in this small configuration gap. [[cache-specific-config]] -=== How can I set the TTL/TTI/Eviction policy/XXX feature? - -Directly through your cache provider. The cache abstraction is... well, an abstraction -not a cache implementation. The solution you are using might support various data -policies and different topologies which other solutions do not (take for example the JDK -`ConcurrentHashMap`) - exposing that in the cache abstraction would be useless simply -because there would no backing support. Such functionality should be controlled directly -through the backing cache, when configuring it or through its native API. - +=== How can I Set the TTL/TTI/Eviction policy/XXX feature? + +Directly through your cache provider. The cache abstraction is an abstraction, +not a cache implementation. The solution you use might support various data +policies and different topologies that other solutions do not support (for example, the JDK +`ConcurrentHashMap` -- exposing that in the cache abstraction would be useless +because there would no backing support). Such functionality should be controlled directly +through the backing cache (when configuring it) or through its native API. diff --git a/src/docs/asciidoc/languages/dynamic-languages.adoc b/src/docs/asciidoc/languages/dynamic-languages.adoc index 842834713a..4549c3bcb1 100644 --- a/src/docs/asciidoc/languages/dynamic-languages.adoc +++ b/src/docs/asciidoc/languages/dynamic-languages.adoc @@ -1,18 +1,13 @@ [[dynamic-language]] = Dynamic Language Support - - -[[dynamic-language-introduction]] -== Introduction - -Spring 2.0 introduces comprehensive support for using classes and objects that have been -defined using a dynamic language (such as JRuby) with Spring. This support allows you to -write any number of classes in a supported dynamic language, and have the Spring -container transparently instantiate, configure and dependency inject the resulting +Spring 2.0 introduced comprehensive support for using classes and objects that have been +defined by using a dynamic language (such as JRuby) with Spring. This support lets you +write any number of classes in a supported dynamic language and have the Spring +container transparently instantiate, configure, and dependency inject the resulting objects. -The dynamic languages currently supported are: +Spring currently supports the following dynamic languages: * JRuby 1.5+ * Groovy 1.8+ @@ -20,32 +15,34 @@ The dynamic languages currently supported are: .Why only these languages? **** -The supported languages were chosen because __a)__ the languages have a lot of traction in -the Java enterprise community, __b)__ no requests were made for other languages at the time -that this support was added, and __c)__ the Spring developers were most familiar with -them. +We chose to support these languages because: + +* The languages have a lot of traction in the Java enterprise community. +* No requests were made for other languages at the time that this support was added +* The Spring developers were most familiar with them. **** -Fully working examples of where this dynamic language support can be immediately useful -are described in <>. +You can find fully working examples of where this dynamic language support can be immediately useful +in <>. [[dynamic-language-a-first-example]] -== A first example +== A First Example -This bulk of this chapter is concerned with describing the dynamic language support in +The bulk of this chapter is concerned with describing the dynamic language support in detail. Before diving into all of the ins and outs of the dynamic language support, -let's look at a quick example of a bean defined in a dynamic language. The dynamic -language for this first bean is Groovy (the basis of this example was taken from the -Spring test suite, so if you want to see equivalent examples in any of the other +we look at a quick example of a bean defined in a dynamic language. The dynamic +language for this first bean is Groovy. (The basis of this example was taken from the +Spring test suite. If you want to see equivalent examples in any of the other supported languages, take a look at the source code). -Find below the `Messenger` interface that the Groovy bean is going to be implementing, -and note that this interface is defined in plain Java. Dependent objects that are -injected with a reference to the `Messenger` won't know that the underlying -implementation is a Groovy script. +The next example shows the `Messenger` interface, which the Groovy bean is going to implement. +Note that this interface is defined in plain Java. Dependent objects that are +injected with a reference to the `Messenger` do not know that the underlying +implementation is a Groovy script. The following listing shows the `Messenger` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -57,9 +54,11 @@ implementation is a Groovy script. } ---- +==== -Here is the definition of a class that has a dependency on the `Messenger` interface. +The following example defines a class that has a dependency on the `Messenger` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -79,9 +78,11 @@ Here is the definition of a class that has a dependency on the `Messenger` inter } ---- +==== -Here is an implementation of the `Messenger` interface in Groovy. +The following example implements the `Messenger` interface in Groovy: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -98,16 +99,13 @@ Here is an implementation of the `Messenger` interface in Groovy. } ---- - -Finally, here are the bean definitions that will effect the injection of the -Groovy-defined `Messenger` implementation into an instance of the -`DefaultBookingService` class. +==== [NOTE] ==== To use the custom dynamic language tags to define dynamic-language-backed beans, you need to have the XML Schema preamble at the top of your Spring XML configuration file. -You also need to be using a Spring `ApplicationContext` implementation as your IoC +You also need to use a Spring `ApplicationContext` implementation as your IoC container. Using the dynamic-language-backed beans with a plain `BeanFactory` implementation is supported, but you have to manage the plumbing of the Spring internals to do so. @@ -116,6 +114,11 @@ For more information on schema-based configuration, see <>. ==== +Finally, the following example shows the bean definitions that effect the injection of the +Groovy-defined `Messenger` implementation into an instance of the +`DefaultBookingService` class: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -138,60 +141,64 @@ XML Schema-based configuration>>. ---- +==== The `bookingService` bean (a `DefaultBookingService`) can now use its private -`messenger` member variable as normal because the `Messenger` instance that was injected -into it __is__ a `Messenger` instance. There is nothing special going on here, just +`messenger` member variable as normal, because the `Messenger` instance that was injected +into it is a `Messenger` instance. There is nothing special going on here -- just plain Java and plain Groovy. -Hopefully the above XML snippet is self-explanatory, but don't worry unduly if it isn't. -Keep reading for the in-depth detail on the whys and wherefores of the above +Hopefully, the preceding XML snippet is self-explanatory, but do not worry unduly if it is not. +Keep reading for the in-depth detail on the whys and wherefores of the preceding configuration. [[dynamic-language-beans]] -== Defining beans that are backed by dynamic languages +== Defining Beans that Are Backed by Dynamic Languages -This section describes exactly how you define Spring managed beans in any of the +This section describes exactly how you define Spring-managed beans in any of the supported dynamic languages. -Please note that this chapter does not attempt to explain the syntax and idioms of the +Note that this chapter does not attempt to explain the syntax and idioms of the supported dynamic languages. For example, if you want to use Groovy to write certain of -the classes in your application, then the assumption is that you already know Groovy. If -you need further details about the dynamic languages themselves, please -consult <> at the end of this chapter. +the classes in your application, we assume that you already know Groovy. If +you need further details about the dynamic languages themselves, see +<> at the end of this chapter. + [[dynamic-language-beans-concepts]] -=== Common concepts +=== Common Concepts The steps involved in using dynamic-language-backed beans are as follows: -* Write the test for the dynamic language source code (naturally) -* __Then__ write the dynamic language source code itself :) -* Define your dynamic-language-backed beans using the appropriate `` - element in the XML configuration (you can of course define such beans programmatically - using the Spring API - although you will have to consult the source code for - directions on how to do this as this type of advanced configuration is not covered in - this chapter). Note this is an iterative step. You will need at least one bean - definition per dynamic language source file (although the same dynamic language source - file can of course be referenced by multiple bean definitions). +. Write the test for the dynamic language source code (naturally). +. Then write the dynamic language source code itself. +. Define your dynamic-language-backed beans by using the appropriate `` + element in the XML configuration (you can define such beans programmatically by + using the Spring API, although you will have to consult the source code for + directions on how to do this, as this chapter does not cover this type of advanced configuration). + Note that this is an iterative step. You need at least one bean + definition for each dynamic language source file (although multiple bean definitions can reference the same dynamic language source + file). The first two steps (testing and writing your dynamic language source files) are beyond -the scope of this chapter. Refer to the language specification and / or reference manual +the scope of this chapter. See the language specification and reference manual for your chosen dynamic language and crack on with developing your dynamic language -source files. You __will__ first want to read the rest of this chapter though, as +source files. You first want to read the rest of this chapter, though, as Spring's dynamic language support does make some (small) assumptions about the contents of your dynamic language source files. + + [[dynamic-language-beans-concepts-xml-language-element]] ==== The element -The final step involves defining dynamic-language-backed bean definitions, one for each +The final step in the list in the <> involves defining dynamic-language-backed bean definitions, one for each bean that you want to configure (this is no different from normal JavaBean configuration). However, instead of specifying the fully qualified classname of the -class that is to be instantiated and configured by the container, you use the +class that is to be instantiated and configured by the container, you can use the `` element to define the dynamic language-backed bean. Each of the supported languages has a corresponding `` element: @@ -202,42 +209,42 @@ Each of the supported languages has a corresponding `` element: The exact attributes and child elements that are available for configuration depends on exactly which language the bean has been defined in (the language-specific sections -below provide the full lowdown on this). +later in this chapter detail this). + + [[dynamic-language-refreshable-beans]] -==== Refreshable beans +==== Refreshable Beans -One of the (if not __the__) most compelling value adds of the dynamic language support -in Spring is the__'refreshable bean'__ feature. +One of the (and perhaps the single) most compelling value adds of the dynamic language support +in Spring is the "`refreshable bean`" feature. -A refreshable bean is a dynamic-language-backed bean that with a small amount of +A refreshable bean is a dynamic-language-backed bean. With a small amount of configuration, a dynamic-language-backed bean can monitor changes in its underlying -source file resource, and then reload itself when the dynamic language source file is -changed (for example when a developer edits and saves changes to the file on the -filesystem). +source file resource and then reload itself when the dynamic language source file is +changed (for example, when you edit and save changes to the file on the +file system). -This allows a developer to deploy any number of dynamic language source files as part of +This lets you deploy any number of dynamic language source files as part of an application, configure the Spring container to create beans backed by dynamic -language source files (using the mechanisms described in this chapter), and then later, -as requirements change or some other external factor comes into play, simply edit a -dynamic language source file and have any change they make reflected in the bean that is +language source files (using the mechanisms described in this chapter), and (later, +as requirements change or some other external factor comes into play) edit a +dynamic language source file and have any change they make be reflected in the bean that is backed by the changed dynamic language source file. There is no need to shut down a running application (or redeploy in the case of a web application). The -dynamic-language-backed bean so amended will pick up the new state and logic from the +dynamic-language-backed bean so amended picks up the new state and logic from the changed dynamic language source file. -[NOTE] -==== -Please note that this feature is __off__ by default. -==== +NOTE: This feature is off by default. -Let's take a look at an example to see just how easy it is to start using refreshable -beans. To __turn on__ the refreshable beans feature, you simply have to specify exactly -__one__ additional attribute on the `` element of your bean definition. -So if we stick with <> from earlier in this -chapter, here's what we would change in the Spring XML configuration to effect +Now we can take a look at an example to see how easy it is to start using refreshable +beans. To turn on the refreshable beans feature, you have to specify exactly +one additional attribute on the `` element of your bean definition. +So, if we stick with <> from earlier in this +chapter, the following example shows what we would change in the Spring XML configuration to effect refreshable beans: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -256,21 +263,25 @@ refreshable beans: ---- +==== -That really is all you have to do. The `'refresh-check-delay'` attribute defined on the -`'messenger'` bean definition is the number of milliseconds after which the bean will be +That really is all you have to do. The `refresh-check-delay` attribute defined on the +`messenger` bean definition is the number of milliseconds after which the bean is refreshed with any changes made to the underlying dynamic language source file. You can turn off the refresh behavior by assigning a negative value to the -`'refresh-check-delay'` attribute. Remember that, by default, the refresh behavior is -disabled. If you don't want the refresh behavior, then simply don't define the attribute. - -If we then run the following application we can exercise the refreshable feature; please -do excuse the __'jumping-through-hoops-to-pause-the-execution'__ shenanigans in this -next slice of code. The `System.in.read()` call is only there so that the execution of -the program pauses while I (the author) go off and edit the underlying dynamic language -source file so that the refresh will trigger on the dynamic-language-backed bean when +`refresh-check-delay` attribute. Remember that, by default, the refresh behavior is +disabled. If you do not want the refresh behavior, do not define the attribute. + +If we then run the following application, we can exercise the refreshable feature (Please +do excuse the "`jumping-through-hoops-to-pause-the-execution`" shenanigans in this +next slice of code.) The `System.in.read()` call is only there so that the execution of +the program pauses while you (the developer in this scenario) go off and edit the underlying dynamic language +source file so that the refresh triggers on the dynamic-language-backed bean when the program resumes execution. +The following listing shows this sample application: + +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -290,12 +301,14 @@ the program resumes execution. } } ---- +==== -Let's assume then, for the purposes of this example, that all calls to the +Assume then, for the purposes of this example, that all calls to the `getMessage()` method of `Messenger` implementations have to be changed such that the -message is surrounded by quotes. Below are the changes that I (the author) make to the -`Messenger.groovy` source file when the execution of the program is paused. +message is surrounded by quotation marks. The following listing shows the changes that you (the developer) should make to the +`Messenger.groovy` source file when the execution of the program is paused: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -315,38 +328,42 @@ message is surrounded by quotes. Below are the changes that I (the author) make } } ---- +==== -When the program executes, the output before the input pause will be __I Can Do The -Frug__. After the change to the source file is made and saved, and the program resumes +When the program runs, the output before the input pause will be `I Can Do The +Frug`. After the change to the source file is made and saved and the program resumes execution, the result of calling the `getMessage()` method on the -dynamic-language-backed `Messenger` implementation will be __'I Can Do The Frug'__ -(notice the inclusion of the additional quotes). +dynamic-language-backed `Messenger` implementation is `'I Can Do The Frug'` +(notice the inclusion of the additional quotation marks). -It is important to understand that changes to a script will __not__ trigger a refresh if -the changes occur within the window of the `'refresh-check-delay'` value. It is equally -important to understand that changes to the script are __not__ actually 'picked up' until +Changes to a script do not trigger a refresh if +the changes occur within the window of the `refresh-check-delay` value. +Changes to the script are not actually picked up until a method is called on the dynamic-language-backed bean. It is only when a method is called on a dynamic-language-backed bean that it checks to see if its underlying script -source has changed. Any exceptions relating to refreshing the script (such as -encountering a compilation error, or finding that the script file has been deleted) will -result in a __fatal__ exception being propagated to the calling code. - -The refreshable bean behavior described above does __not__ apply to dynamic language -source files defined using the `` element notation (see -<>). Additionally, it __only__ applies to beans where -changes to the underlying source file can actually be detected; for example, by code +source has changed. Any exceptions that relate to refreshing the script (such as +encountering a compilation error or finding that the script file has been deleted) +results in a fatal exception being propagated to the calling code. + +The refreshable bean behavior described earlier does not apply to dynamic language +source files defined with the `` element notation (see +<>). Additionally, it applies only to beans where +changes to the underlying source file can actually be detected (for example, by code that checks the last modified date of a dynamic language source file that exists on the -filesystem. +file system). + + [[dynamic-language-beans-inline]] -==== Inline dynamic language source files +==== Inline Dynamic Language Source Files -The dynamic language support can also cater for dynamic language source files that are +The dynamic language support can also cater to dynamic language source files that are embedded directly in Spring bean definitions. More specifically, the -`` element allows you to define dynamic language source immediately -inside a Spring configuration file. An example will perhaps make the inline script -feature crystal clear: +`` element lets you define dynamic language source immediately +inside a Spring configuration file. An example might clarify how the inline script +feature works: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -365,6 +382,7 @@ feature crystal clear: ---- +==== If we put to one side the issues surrounding whether it is good practice to define dynamic language source inside a Spring configuration file, the `` @@ -373,16 +391,20 @@ Spring `Validator` implementation to a Spring MVC `Controller`. This is but a mo work using inline source. (See <> for such an example.) + + [[dynamic-language-beans-ctor-injection]] -==== Understanding Constructor Injection in the context of dynamic-language-backed beans +==== Understanding Constructor Injection in the Context of Dynamic-language-backed Beans -There is one __very__ important thing to be aware of with regard to Spring's dynamic -language support. Namely, it is not (currently) possible to supply constructor arguments -to dynamic-language-backed beans (and hence constructor-injection is not available for +There is one very important thing to be aware of with regard to Spring's dynamic +language support. Namely, you can not (currently) supply constructor arguments +to dynamic-language-backed beans (and, hence, constructor-injection is not available for dynamic-language-backed beans). In the interests of making this special handling of constructors and properties 100% clear, the following mixture of code and configuration -will __not__ work. +does not work: +.An approach that cannot work +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -421,36 +443,41 @@ will __not__ work. ---- +==== -In practice this limitation is not as significant as it first appears since setter +In practice this limitation is not as significant as it first appears, since setter injection is the injection style favored by the overwhelming majority of developers -anyway (let's leave the discussion as to whether that is a good thing to another day). +(we leave the discussion as to whether that is a good thing to another day). + [[dynamic-language-beans-groovy]] -=== Groovy beans +=== Groovy Beans + +This section describes how to use beans defined in Groovy in Spring. .The Groovy library dependencies **** The Groovy scripting support in Spring requires the following libraries to be on the -classpath of your application. +classpath of your application: * `groovy-1.8.jar` * `asm-3.2.jar` * `antlr-2.7.7.jar` **** -From the Groovy homepage... +The Groovy homepage includes the following description: -"__Groovy is an agile dynamic language for the Java 2 Platform that has many of the +"`Groovy is an agile dynamic language for the Java 2 Platform that has many of the features that people like so much in languages like Python, Ruby and Smalltalk, making -them available to Java developers using a Java-like syntax. __" +them available to Java developers using a Java-like syntax.`" -If you have read this chapter straight from the top, you will already have +If you have read this chapter straight from the top, you have already <> of a Groovy-dynamic-language-backed -bean. Let's look at another example (again using an example from the Spring test suite). +bean. Now consider another example (again using an example from the Spring test suite): +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -462,9 +489,11 @@ bean. Let's look at another example (again using an example from the Spring test } ---- +==== -Here is an implementation of the `Calculator` interface in Groovy. +The following example implements the `Calculator` interface in Groovy: +==== [source,groovy,indent=0] [subs="verbatim,quotes"] ---- @@ -479,7 +508,11 @@ Here is an implementation of the `Calculator` interface in Groovy. } ---- +==== +The following bean definition uses the calculator defined in Groovy: + +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -488,9 +521,11 @@ Here is an implementation of the `Calculator` interface in Groovy. ---- +==== -Lastly, here is a small application to exercise the above configuration. +Finally, the following small application exercises the preceding configuration: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -508,25 +543,30 @@ Lastly, here is a small application to exercise the above configuration. } } ---- +==== -The resulting output from running the above program will be (unsurprisingly) __10__. -(Exciting example, huh? Remember that the intent is to illustrate the concept. Please -consult the dynamic language showcase project for a more complex example, or indeed +The resulting output from running the above program is (unsurprisingly) `10`. +(For more interesting examples, +see the dynamic language showcase project for a more complex example or see the examples <> later in this chapter). -It is important that you __do not__ define more than one class per Groovy source file. -While this is perfectly legal in Groovy, it is (arguably) a bad practice: in the -interests of a consistent approach, you should (in the opinion of this author) respect +You must not define more than one class per Groovy source file. +While this is perfectly legal in Groovy, it is (arguably) a bad practice. In the +interests of a consistent approach, you should (in the opinion of the Spring team) respect the standard Java conventions of one (public) class per source file. + + [[dynamic-language-beans-groovy-customizer]] -==== Customizing Groovy objects via a callback +==== Customizing Groovy Objects by Using a Callback -The `GroovyObjectCustomizer` interface is a callback that allows you to hook additional +The `GroovyObjectCustomizer` interface is a callback that lets you hook additional creation logic into the process of creating a Groovy-backed bean. For example, -implementations of this interface could invoke any required initialization method(s), or -set some default property values, or specify a custom `MetaClass`. +implementations of this interface could invoke any required initialization methods, +set some default property values, or specify a custom `MetaClass`. The following listing +shows the `GroovyObjectCustomizer` interface definition: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -535,13 +575,15 @@ set some default property values, or specify a custom `MetaClass`. void customize(GroovyObject goo); } ---- +==== -The Spring Framework will instantiate an instance of your Groovy-backed bean, and will -then pass the created `GroovyObject` to the specified `GroovyObjectCustomizer` if one -has been defined. You can do whatever you like with the supplied `GroovyObject` -reference: it is expected that the setting of a custom `MetaClass` is what most folks -will want to do with this callback, and you can see an example of doing that below. +The Spring Framework instantiates an instance of your Groovy-backed bean and +then passes the created `GroovyObject` to the specified `GroovyObjectCustomizer` (if one +has been defined). You can do whatever you like with the supplied `GroovyObject` +reference. We expect that most people want to set a custom `MetaClass` with this callback, +and the following example shows how to do so: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -561,12 +603,15 @@ will want to do with this callback, and you can see an example of doing that bel } ---- +==== A full discussion of meta-programming in Groovy is beyond the scope of the Spring -reference manual. Consult the relevant section of the Groovy reference manual, or do a -search online: there are plenty of articles concerning this topic. Actually making use -of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace support. +reference manual. See the relevant section of the Groovy reference manual or do a +search online. Plenty of articles address this topic. Actually, making use +of a `GroovyObjectCustomizer` is easy if you use the Spring namespace support, as the +following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -578,10 +623,12 @@ of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace supp script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy" customizer-ref="tracingCustomizer"/> ---- +==== -If you are not using the Spring namespace support, you can still use the -`GroovyObjectCustomizer` functionality. +If you do not use the Spring namespace support, you can still use the +`GroovyObjectCustomizer` functionality, as the following example shows: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -595,47 +642,49 @@ If you are not using the Spring namespace support, you can still use the ---- - -[NOTE] ==== -As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer` + +NOTE: As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer` (such as an `ImportCustomizer`) or even a full Groovy `CompilerConfiguration` object in the same place as Spring's `GroovyObjectCustomizer`. -==== + [[dynamic-language-beans-bsh]] -=== BeanShell beans +=== BeanShell Beans + +This section describes how to use BeanShell beans in Spring. .The BeanShell library dependencies **** The BeanShell scripting support in Spring requires the following libraries to be on the -classpath of your application. +classpath of your application: * `bsh-2.0b4.jar` **** -From the BeanShell homepage... +The BeanShell homepage includes the following description: {JB} -"__BeanShell is a small, free, embeddable Java source interpreter with dynamic language +"`BeanShell is a small, free, embeddable Java source interpreter with dynamic language features, written in Java. BeanShell dynamically executes standard Java syntax and extends it with common scripting conveniences such as loose types, commands, and method -closures like those in Perl and JavaScript.__" +closures like those in Perl and JavaScript.`" In contrast to Groovy, BeanShell-backed bean definitions require some (small) additional configuration. The implementation of the BeanShell dynamic language support in Spring is -interesting in that what happens is this: Spring creates a JDK dynamic proxy -implementing all of the interfaces that are specified in the `'script-interfaces'` -attribute value of the `` element (this is why you __must__ supply at least -one interface in the value of the attribute, and (accordingly) program to interfaces -when using BeanShell-backed beans). This means that every method call on a -BeanShell-backed object is going through the JDK dynamic proxy invocation mechanism. +interesting, because Spring creates a JDK dynamic proxy +that implements all of the interfaces that are specified in the `script-interfaces` +attribute value of the `` element (this is why you must supply at least +one interface in the value of the attribute, and, consequently, program to interfaces +when you use BeanShell-backed beans). This means that every method call on a +BeanShell-backed object goes through the JDK dynamic proxy invocation mechanism. -Let's look at a fully working example of using a BeanShell-based bean that implements -the `Messenger` interface that was defined earlier in this chapter (repeated below for -your convenience). +Now we can show a fully working example of using a BeanShell-based bean that implements +the `Messenger` interface that was defined earlier in this chapter. We again show the +definition of the `Messenger` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -647,10 +696,12 @@ your convenience). } ---- +==== -Here is the BeanShell 'implementation' (the term is used loosely here) of the -`Messenger` interface. +The following example shows the BeanShell "`implementation`" (we use the term loosely here) of the +`Messenger` interface: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -664,10 +715,12 @@ Here is the BeanShell 'implementation' (the term is used loosely here) of the message = aMessage; } ---- +==== -And here is the Spring XML that defines an 'instance' of the above 'class' (again, the -term is used very loosely here). +The following exxample shows the Spring XML that defines an "`instance`" of the above "`class`" (again, +we use these terms very loosely here): +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -677,6 +730,7 @@ term is used very loosely here). ---- +==== See <> for some scenarios where you might want to use BeanShell-based beans. @@ -687,40 +741,39 @@ BeanShell-based beans. == Scenarios The possible scenarios where defining Spring managed beans in a scripting language would -be beneficial are, of course, many and varied. This section describes two possible use +be beneficial are many and varied. This section describes two possible use cases for the dynamic language support in Spring. + [[dynamic-language-scenarios-controllers]] === Scripted Spring MVC Controllers -One group of classes that may benefit from using dynamic-language-backed beans is that +One group of classes that can benefit from using dynamic-language-backed beans is that of Spring MVC controllers. In pure Spring MVC applications, the navigational flow -through a web application is to a large extent determined by code encapsulated within +through a web application is, to a large extent, determined by code encapsulated within your Spring MVC controllers. As the navigational flow and other presentation layer logic of a web application needs to be updated to respond to support issues or changing business requirements, it may well be easier to effect any such required changes by editing one or more dynamic language source files and seeing those changes being immediately reflected in the state of a running application. -Remember that in the lightweight architectural model espoused by projects such as -Spring, you are typically aiming to have a really __thin__ presentation layer, with all +Remember that, in the lightweight architectural model espoused by projects such as +Spring, you typically aim to have a really thin presentation layer, with all the meaty business logic of an application being contained in the domain and service -layer classes. Developing Spring MVC controllers as dynamic-language-backed beans allows -you to change presentation layer logic by simply editing and saving text files; any -changes to such dynamic language source files will (depending on the configuration) -automatically be reflected in the beans that are backed by dynamic language source files. +layer classes. Developing Spring MVC controllers as dynamic-language-backed beans lets +you change presentation layer logic by editing and saving text files. Any +changes to such dynamic language source files is (depending on the configuration) +automatically reflected in the beans that are backed by dynamic language source files. -[NOTE] -==== -In order to effect this automatic 'pickup' of any changes to dynamic-language-backed -beans, you will have had to enable the 'refreshable beans' functionality. See +NOTE: To effect this automatic "`pickup`" of any changes to dynamic-language-backed +beans, you have to enable the "`refreshable beans`" functionality. See <> for a full treatment of this feature. -==== -Find below an example of an `org.springframework.web.servlet.mvc.Controller` implemented -using the Groovy dynamic language. +The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented +by using the Groovy dynamic language: +==== [source,java,indent=0] [subs="verbatim,quotes"] ---- @@ -756,34 +809,34 @@ using the Groovy dynamic language. ---- +==== + [[dynamic-language-scenarios-validators]] === Scripted Validators Another area of application development with Spring that may benefit from the -flexibility afforded by dynamic-language-backed beans is that of validation. It __may__ -be easier to express complex validation logic using a loosely typed dynamic language +flexibility afforded by dynamic-language-backed beans is that of validation. It can +be easier to express complex validation logic by using a loosely typed dynamic language (that may also have support for inline regular expressions) as opposed to regular Java. -Again, developing validators as dynamic-language-backed beans allows you to change -validation logic by simply editing and saving a simple text file; any such changes will -(depending on the configuration) automatically be reflected in the execution of a +Again, developing validators as dynamic-language-backed beans lets you change +validation logic by editing and saving a simple text file. Any such changes is +(depending on the configuration) automatically reflected in the execution of a running application and would not require the restart of an application. -[NOTE] -==== -Please note that in order to effect the automatic 'pickup' of any changes to -dynamic-language-backed beans, you will have had to enable the 'refreshable beans' +NOTE: To effect the automatic "`pickup`" of any changes to +dynamic-language-backed beans, you have to enable the 'refreshable beans' feature. See <> for a full and detailed treatment of this feature. -==== -Find below an example of a Spring `org.springframework.validation.Validator` implemented -using the Groovy dynamic language. (See <> for a discussion of the -`Validator` interface.) +`Validator` interface): +==== [source,groovy,indent=0] [subs="verbatim,quotes"] ---- @@ -806,43 +859,47 @@ Validation using Spring’s Validator interface>> for a discussion of the } ---- +==== [[dynamic-language-final-notes]] -== Bits and bobs +== Additional Details + +This last section contains some additional details related to the dynamic language support. -This last section contains some bits and bobs related to the dynamic language support. [[dynamic-language-final-notes-aop]] -=== AOP - advising scripted beans +=== AOP -- Advising Scripted Beans -It is possible to use the Spring AOP framework to advise scripted beans. The Spring AOP +You can use the Spring AOP framework to advise scripted beans. The Spring AOP framework actually is unaware that a bean that is being advised might be a scripted -bean, so all of the AOP use cases and functionality that you may be using or aim to use -will work with scripted beans. There is just one (small) thing that you need to be aware -of when advising scripted beans... you cannot use class-based proxies, you must +bean, so all of the AOP use cases and functionality that you use (or aim to use) +work with scripted beans. +When you advise scripted beans, you cannot use class-based proxies. You must use <>. -You are of course not just limited to advising scripted beans... you can also write +You are not limited to advising scripted beans. You can also write aspects themselves in a supported dynamic language and use such beans to advise other Spring beans. This really would be an advanced use of the dynamic language support though. + [[dynamic-language-final-notes-scopes]] === Scoping -In case it is not immediately obvious, scripted beans can of course be scoped just like -any other bean. The `scope` attribute on the various `` elements allows -you to control the scope of the underlying scripted bean, just as it does with a regular -bean. (The default scope is <>, just as it is -with 'regular' beans.) +In case it is not immediately obvious, scripted beans can be scoped in the same way as +any other bean. The `scope` attribute on the various `` elements lets +you control the scope of the underlying scripted bean, as it does with a regular +bean. (The default scope is <>, as it is +with "`regular`" beans.) -Find below an example of using the `scope` attribute to define a Groovy bean scoped as -a <>. +The following example uses the `scope` attribute to define a Groovy bean scoped as +a <>: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -863,28 +920,30 @@ a <>. ---- +==== See <> in <> -for a fuller discussion of the scoping support in the Spring Framework. +for a full discussion of the scoping support in the Spring Framework. [[xsd-schemas-lang]] -=== The lang XML schema +=== The `lang` XML schema -The `lang` tags in Spring XML configuration deal with exposing objects that have been written -in a dynamic language such as JRuby or Groovy as beans in the Spring container. +The `lang` elements in Spring XML configuration deal with exposing objects that have been written +in a dynamic language (such as JRuby or Groovy) as beans in the Spring container. -These tags (and the dynamic language support) are comprehensively covered in the chapter -entitled <>. -Please do consult that chapter for full details on this support and the `lang` tags themselves. +These elements (and the dynamic language support) are comprehensively covered in +<>. +See that chapter for full details on this support and the `lang` elements. -In the interest of completeness, to use the tags in the `lang` schema, you need to have -the following preamble at the top of your Spring XML configuration file; the text in the +To use the elements in the `lang` schema, you need to have +the following preamble at the top of your Spring XML configuration file. The text in the following snippet references the correct schema so that the tags in the `lang` namespace -are available to you. +are available to you: +==== [source,xml,indent=0] [subs="verbatim,quotes"] ---- @@ -897,15 +956,15 @@ are available to you. ---- - +==== [[dynamic-language-resources]] == Further Resources -Find below links to further resources about the various dynamic languages described in -this chapter. +The following links go to further resources about the various dynamic languages described in +this chapter: * The http://jruby.org/[JRuby] homepage * The http://www.groovy-lang.org/[Groovy] homepage diff --git a/src/docs/asciidoc/languages/groovy.adoc b/src/docs/asciidoc/languages/groovy.adoc index 992f60019c..d274f61211 100644 --- a/src/docs/asciidoc/languages/groovy.adoc +++ b/src/docs/asciidoc/languages/groovy.adoc @@ -1,7 +1,7 @@ [[groovy]] = Apache Groovy -Groovy is a powerful, optionally typed and dynamic language, with static-typing and static +Groovy is a powerful, optionally typed, and dynamic language, with static-typing and static compilation capabilities. It offers a concise syntax and integrates smoothly with any existing Java application. @@ -9,5 +9,5 @@ The Spring Framework provides a dedicated `ApplicationContext` that supports a G Bean Definition DSL. For more details, see <>. -Further support for Groovy including beans written in Groovy, refreshable script beans, -and more is available in next the section <>. +Further support for Groovy, including beans written in Groovy, refreshable script beans, +and more is available in <>. diff --git a/src/docs/asciidoc/languages/kotlin.adoc b/src/docs/asciidoc/languages/kotlin.adoc index f4d9667dc2..b3c61b4b11 100644 --- a/src/docs/asciidoc/languages/kotlin.adoc +++ b/src/docs/asciidoc/languages/kotlin.adoc @@ -1,18 +1,18 @@ [[kotlin]] = Kotlin -https://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms) +https://kotlinlang.org[Kotlin] is a statically typed language that targets the JVM (and other platforms), which allows writing concise and elegant code while providing very good https://kotlinlang.org/docs/reference/java-interop.html[interoperability] with existing libraries written in Java. -The Spring Framework provides first-class support for Kotlin that allows developers to write -Kotlin applications almost as if the Spring Framework was a native Kotlin framework. +The Spring Framework provides first-class support for Kotlin that lets developers write +Kotlin applications almost as if the Spring Framework were a native Kotlin framework. -The easiest way to learn about Spring + Kotlin is to follow +The easiest way to learn about Spring and Kotlin is to follow https://spring.io/guides/tutorials/spring-boot-kotlin/[this comprehensive tutorial]. Feel free to join the #spring channel of http://slack.kotlinlang.org/[Kotlin Slack] or ask a -question with `spring` and `kotlin` tags on +question with `spring` and `kotlin` as tags on https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support. @@ -20,178 +20,163 @@ https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you n [[kotlin-requirements]] == Requirements -Spring Framework supports Kotlin 1.1+ and requires +The Spring Framework supports Kotlin 1.1+ and requires https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib[`kotlin-stdlib`] -(or one of its variants like https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`] +(or one of its variants, such as https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`] for Kotlin 1.1 or https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`] for Kotlin 1.2+) and https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-reflect[`kotlin-reflect`] -to be present on the classpath. They are provided by default if one bootstraps a Kotlin project on +to be present on the classpath. They are provided by default if you bootstrap a Kotlin project on https://start.spring.io/#!language=kotlin[start.spring.io]. - [[kotlin-extensions]] == Extensions Kotlin https://kotlinlang.org/docs/reference/extensions.html[extensions] provide the ability -to extend existing classes with additional functionality. The Spring Framework Kotlin APIs make -use of these extensions to add new Kotlin specific conveniences to existing Spring APIs. +to extend existing classes with additional functionality. The Spring Framework Kotlin APIs +use these extensions to add new Kotlin-specific conveniences to existing Spring APIs. -{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists -and documents all the Kotlin extensions and DSLs available. +The {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/[Spring Framework KDoc API] lists +and documents all available the Kotlin extensions and DSLs. -[NOTE] -==== -Keep in mind that Kotlin extensions need to be imported to be used. This means -for example that the `GenericApplicationContext.registerBean` Kotlin extension -will only be available if `import org.springframework.context.support.registerBean` is imported. +NOTE: Keep in mind that Kotlin extensions need to be imported to be used. This means, +for example, that the `GenericApplicationContext.registerBean` Kotlin extension +is available only if `org.springframework.context.support.registerBean` is imported. That said, similar to static imports, an IDE should automatically suggest the import in most cases. -==== For example, https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters[Kotlin reified type parameters] provide a workaround for JVM https://docs.oracle.com/javase/tutorial/java/generics/erasure.html[generics type erasure], -and Spring Framework provides some extensions to take advantage of this feature. -This allows for a better Kotlin API `RestTemplate`, the new `WebClient` from Spring -WebFlux and for various other APIs. +and the Spring Framework provides some extensions to take advantage of this feature. +This allows for a better Kotlin API `RestTemplate`, for the new `WebClient` from Spring +WebFlux, and for various other APIs. -[NOTE] -==== -Other libraries like Reactor and Spring Data also provide Kotlin extensions +NOTE: Other libraries, such as Reactor and Spring Data, also provide Kotlin extensions for their APIs, thus giving a better Kotlin development experience overall. -==== -To retrieve a list of `Foo` objects in Java, one would normally write: +To retrieve a list of `User` objects in Java, you would normally write the following: +==== [source,java,indent=0] ---- Flux users = client.get().retrieve().bodyToFlux(User.class) ---- +==== -Whilst with Kotlin and Spring Framework extensions, one is able to write: +With Kotlin and the Spring Framework extensions, you can instead write the following: +==== [source,kotlin,indent=0] ---- val users = client.get().retrieve().bodyToFlux() // or (both are equivalent) val users : Flux = client.get().retrieve().bodyToFlux() ---- +==== As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows for shorter syntax. - [[kotlin-null-safety]] == Null-safety -One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety] -- which cleanly deals with `null` values at compile time rather than bumping into the famous +One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety], +which cleanly deals with `null` values at compile time rather than bumping into the famous `NullPointerException` at runtime. This makes applications safer through nullability -declarations and expressing "value or no value" semantics without paying the cost of wrappers like `Optional`. -(Kotlin allows using functional constructs with nullable values; check out this +declarations and expressing "`value or no value`" semantics without paying the cost of wrappers, such as `Optional`. +(Kotlin allows using functional constructs with nullable values. See this http://www.baeldung.com/kotlin-null-safety[comprehensive guide to Kotlin null-safety].) -Although Java does not allow one to express null-safety in its type-system, Spring Framework now +Although Java does not let you express null-safety in its type-system, the Spring Framework provides <> via tooling-friendly annotations declared in the `org.springframework.lang` package. By default, types from Java APIs used in Kotlin are recognized as -https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types] +https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types], for which null-checks are relaxed. -https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR 305 annotations] -+ Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers, -with the advantage of dealing with `null` related issues at compile time. +https://kotlinlang.org/docs/reference/java-interop.html#jsr-305-support[Kotlin support for JSR-305 annotations] +and Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers, +with the advantage of dealing with `null`-related issues at compile time. -[NOTE] -==== -Libraries like Reactor or Spring Data provide null-safe APIs leveraging this feature. -==== +NOTE: Libraries such as Reactor or Spring Data provide null-safe APIs to leverage this feature. -The JSR 305 checks can be configured by adding the `-Xjsr305` compiler flag with the following +You can configure JSR-305 checks by adding the `-Xjsr305` compiler flag with the following options: `-Xjsr305={strict|warn|ignore}`. -For kotlin versions 1.1+, the default behavior is the same to `-Xjsr305=warn`. -The `strict` value is required to have Spring Framework API null-safety taken in account +For kotlin versions 1.1+, the default behavior is the same as `-Xjsr305=warn`. +The `strict` value is required to have Spring Framework API null-safety taken into account in Kotlin types inferred from Spring API but should be used with the knowledge that Spring -API nullability declaration could evolve even between minor releases and more checks may +API nullability declaration could evolve even between minor releases and that more checks may be added in the future). -[NOTE] -==== -Generic type arguments, varargs and array elements nullability are not supported yet, -but should be in an upcoming release, see https://github.com/Kotlin/KEEP/issues/79[this discussion] +NOTE: Generic type arguments, varargs, and array elements nullability are not supported yet, +but should be in an upcoming release. See https://github.com/Kotlin/KEEP/issues/79[this discussion] for up-to-date information. -==== - [[kotlin-classes-interfaces]] -== Classes & Interfaces +== Classes and Interfaces -Spring Framework supports various Kotlin constructs like instantiating Kotlin classes -via primary constructors, immutable classes data binding and function optional parameters +The Spring Framework supports various Kotlin constructs, such as instantiating Kotlin classes +through primary constructors, immutable classes data binding, and function optional parameters with default values. -Kotlin parameter names are recognized via a dedicated `KotlinReflectionParameterNameDiscoverer` +Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`, which allows finding interface method parameter names without requiring the Java 8 `-parameters` -compiler flag enabled during compilation. +compiler flag to be enabled during compilation. -https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module] which is required -for serializing / deserializing JSON data is automatically registered when -found in the classpath and a warning message will be logged if Jackson and Kotlin are -detected without the Jackson Kotlin module present. +The https://github.com/FasterXML/jackson-module-kotlin[Jackson Kotlin module], which is required +for serializing or deserializing JSON data, is automatically registered when +found in the classpath, and a warning message is logged if Jackson and Kotlin are +detected without the Jackson Kotlin module being present. -Configuration classes can be -https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner] +You can declare configuration classes as +https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner], since the later requires a reference to the outer class. - [[kotlin-annotations]] == Annotations -Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety] +The Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety] to determine if a HTTP parameter is required without having to explicitly -define the `required` attribute. That means `@RequestParam name: String?` will be treated -as not required and conversely `@RequestParam name: String` as being required. +define the `required` attribute. That means `@RequestParam name: String?` is treated +as not required and, conversely, `@RequestParam name: String` is treated as being required. This feature is also supported on the Spring Messaging `@Header` annotation. -In a similar fashion, Spring bean injection with `@Autowired`, `@Bean` or `@Inject` uses +In a similar fashion, Spring bean injection with `@Autowired`, `@Bean`, or `@Inject` uses this information to determine if a bean is required or not. -For example, `@Autowired lateinit var foo: Foo` implies that a bean -of type `Foo` must be registered in the application context, while `@Autowired lateinit var foo: Foo?` -won’t raise an error if such bean does not exist. +For example, `@Autowired lateinit var thing: Thing` implies that a bean +of type `Thing` must be registered in the application context, while `@Autowired lateinit var thing: Thing?` +does not raise an error if such a bean does not exist. -Following the same principle, `@Bean fun baz(foo: Foo, bar: Bar?) = Baz(foo, bar)` implies -that a bean of type `Foo` must be registered in the application context while a bean of -type `Bar` may or may not exist. The same behavior applies to autowired constructor parameters. +Following the same principle, `@Bean fun play(toy: Toy, car: Car?) = Baz(toy, Car)` implies +that a bean of type `Toy` must be registered in the application context, while a bean of +type `Car` may or may not exist. The same behavior applies to autowired constructor parameters. -[NOTE] -==== -If you are using bean validation on classes with properties or a primary constructor -parameters, you may need to leverage -https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets] -like `@field:NotNull` or `@get:Size(min=5, max=15)` as described in +NOTE: If you use bean validation on classes with properties or a primary constructor +parameters, you may need to use +https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets[annotation use-site targets], +such as `@field:NotNull` or `@get:Size(min=5, max=15)`, as described in https://stackoverflow.com/a/35853200/1092077[this Stack Overflow response]. -==== - [[kotlin-bean-definition-dsl]] -== Bean definition DSL +== Bean Definition DSL -Spring Framework 5 introduces a new way to register beans in a functional way using lambdas -as an alternative to XML or JavaConfig (`@Configuration` and `@Bean`). In a nutshell, -it makes it possible to register beans with a lambda that acts as a `FactoryBean`. -This mechanism is very efficient as it does not require any reflection or CGLIB proxies. +Spring Framework 5 introduces a new way to register beans in a functional way by using lambdas +as an alternative to XML or Java configuration (`@Configuration` and `@Bean`). In a nutshell, +it lets you register beans with a lambda that acts as a `FactoryBean`. +This mechanism is very efficient, as it does not require any reflection or CGLIB proxies. -In Java, one may for example write: +In Java, you can, for example, write the following: +==== [source,java,indent=0] ---- GenericApplicationContext context = new GenericApplicationContext(); @@ -199,10 +184,12 @@ In Java, one may for example write: context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)) ); ---- +==== -Whilst in Kotlin with reified type parameters and `GenericApplicationContext` -Kotlin extensions one can instead simply write: +In Kotlin, with reified type parameters and `GenericApplicationContext` +Kotlin extensions, you can instead write the following: +==== [source,kotlin,indent=0] ---- val context = GenericApplicationContext().apply { @@ -210,13 +197,15 @@ Kotlin extensions one can instead simply write: registerBean { Bar(it.getBean()) } } ---- +==== In order to allow a more declarative approach and cleaner syntax, Spring Framework provides a {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.context.support/-bean-definition-dsl/[Kotlin bean definition DSL] -It declares an `ApplicationContextInitializer` via a clean declarative API -which enables one to deal with profiles and `Environment` for customizing -how beans are registered. +It declares an `ApplicationContextInitializer` through a clean declarative API, +which lets you deal with profiles and `Environment` for customizing +how beans are registered. The following example creates a `Play` profile: +==== [source,kotlin,indent=0] ---- fun beans() = beans { @@ -243,17 +232,20 @@ how beans are registered. setSuffix(suffix) } } - profile("foo") { - bean() + profile("play") { + bean() } } ---- +==== -In this example, `bean()` is using autowiring by constructor and `ref()` +In the preceding example, `bean()` uses autowiring by constructor, and `ref()` is a shortcut for `applicationContext.getBean(Routes::class.java)`. -This `beans()` function can then be used to register beans on the application context. +You can then use this `beans()` function to register beans on the application context, +as the following example shows: +==== [source,kotlin,indent=0] ---- val context = GenericApplicationContext().apply { @@ -261,25 +253,19 @@ This `beans()` function can then be used to register beans on the application co refresh() } ---- - -[NOTE] -==== -This DSL is programmatic, thus it allows custom registration logic of beans -via an `if` expression, a `for` loop or any other Kotlin constructs. ==== +NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans +through an `if` expression, a `for` loop, or any other Kotlin constructs. + See https://github.com/sdeleuze/spring-kotlin-functional/blob/master/src/main/kotlin/functional/Beans.kt[spring-kotlin-functional beans declaration] for a concrete example. -[NOTE] -==== -Spring Boot is based on Java Config and -https://github.com/spring-projects/spring-boot/issues/8115[does not provide specific support for functional bean definition yet], -but one can experimentally use functional bean definitions via Spring Boot's `ApplicationContextInitializer` support, -see https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer] +NOTE: Spring Boot is based on Java configuration and +https://github.com/spring-projects/spring-boot/issues/8115[does not yet provide specific support for functional bean definition], +but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support. +See https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer] for more details and up-to-date information. -==== - @@ -292,9 +278,10 @@ for more details and up-to-date information. Spring Framework now comes with a {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL] -that allows one to leverage the <> for writing clean and idiomatic Kotlin code: +that lets you use the <> to write clean and idiomatic Kotlin code, as the following example shows: +==== [source,kotlin,indent=0] ---- router { @@ -314,37 +301,36 @@ API>> for writing clean and idiomatic Kotlin code: resources("/**", ClassPathResource("static/")) } ---- - -[NOTE] ==== -This DSL is programmatic, thus it allows custom registration logic of beans -via an `if` expression, a `for` loop or any other Kotlin constructs. That can be useful when routes need to be registered + +NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans +through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful when you need to register routes depending on dynamic data (for example, from a database). -==== See https://github.com/mixitconf/mixit/tree/bad6b92bce6193f9b3f696af9d416c276501dbf1/src/main/kotlin/mixit/web/routes[MiXiT project routes] for a concrete example. -=== Kotlin Script templates +=== Kotlin Script Templates As of version 4.3, Spring Framework provides a -http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/view/script/ScriptTemplateView.html[ScriptTemplateView] -to render templates using script engines that supports +http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/view/script/ScriptTemplateView.html[`ScriptTemplateView`] +to render templates by using script engines. It supports https://www.jcp.org/en/jsr/detail?id=223[JSR-223]. Spring Framework 5 goes even further by extending this feature to WebFlux and supporting https://jira.spring.io/browse/SPR-15064[i18n and nested templates]. -Kotlin provides similar support and allows the rendering of Kotlin based templates, see +Kotlin provides similar support and allows the rendering of Kotlin-based templates. See https://github.com/spring-projects/spring-framework/commit/badde3a479a53e1dd0777dd1bd5b55cb1021cf9e[this commit] for details. -This enables some interesting use cases - like writing type-safe templates using -https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or simply using Kotlin multiline `String` with interpolation. +This enables some interesting use cases - such as writing type-safe templates by using +https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or by a using Kotlin multiline `String` with interpolation. -This can allow one to write Kotlin templates with full autocompletion and -refactoring support in a supported IDE: +This can let you write Kotlin templates with full autocompletion and +refactoring support in a supported IDE, as the following example shows: +==== [source,kotlin,indent=0] ---- import io.spring.demo.* @@ -358,40 +344,40 @@ refactoring support in a supported IDE: ${include("footer")} """ ---- +==== -See https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example +See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example project for more details. - [[kotlin-spring-projects-in-kotlin]] -== Spring projects in Kotlin +== Spring Projects in Kotlin -This section provides focus on some specific hints and recommendations worth -knowing when developing Spring projects in Kotlin. +This section provides some specific hints and recommendations worth +for developing Spring projects in Kotlin. -=== Final by default +=== Final by Default By default, https://discuss.kotlinlang.org/t/classes-final-by-default/166[all classes in Kotlin are `final`]. -The `open` modifier on a class is the opposite of Java's `final`: it allows others to +The `open` modifier on a class is the opposite of Java's `final`: It allows others to inherit from this class. This also applies to member functions, in that they need to be marked as `open` to be overridden. -Whilst Kotlin's JVM-friendly design is generally frictionless with Spring, -this specific Kotlin feature can prevent the application from starting, if this fact is not taken in -consideration. This is because Spring beans are normally proxied by CGLIB -- such as `@Configuration` classes - which need to be inherited at runtime for technical reasons. +While Kotlin's JVM-friendly design is generally frictionless with Spring, +this specific Kotlin feature can prevent the application from starting, if this fact is not taken into +consideration. This is because Spring beans +(such as `@Configuration` classes which need to be inherited at runtime for technical reasons) are normally proxied by CGLIB. The workaround was to add an `open` keyword on each class and member -functions of Spring beans proxied by CGLIB such as `@Configuration` classes, which can +function of Spring beans that are proxied by CGLIB (such as `@Configuration` classes), which can quickly become painful and is against the Kotlin principle of keeping code concise and predictable. Fortunately, Kotlin now provides a https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin[`kotlin-spring`] -plugin, a preconfigured version of `kotlin-allopen` plugin that automatically opens classes -and their member functions for types annotated or meta-annotated with one of the following +plugin (a preconfigured version of the `kotlin-allopen` plugin) that automatically opens classes +and their member functions for types that are annotated or meta-annotated with one of the following annotations: * `@Component` @@ -400,35 +386,38 @@ annotations: * `@Cacheable` Meta-annotations support means that types annotated with `@Configuration`, `@Controller`, -`@RestController`, `@Service` or `@Repository` are automatically opened since these +`@RestController`, `@Service`, or `@Repository` are automatically opened since these annotations are meta-annotated with `@Component`. -http://start.spring.io/#!language=kotlin[start.spring.io] enables it by default, so in practice -you will be able to write your Kotlin beans without any additional `open` keyword, like in Java. +http://start.spring.io/#!language=kotlin[start.spring.io] enables it by default, so, in practice, +you can write your Kotlin beans without any additional `open` keyword, as in Java. -=== Using immutable class instances for persistence +=== Using Immutable Class Instances for Persistence -In Kotlin, it is very convenient and considered best practice to declare read-only properties +In Kotlin, it is convenient and considered to be a best practice to declare read-only properties within the primary constructor, as in the following example: +==== [source,kotlin,indent=0] ---- class Person(val name: String, val age: Int) ---- +==== You can optionally add https://kotlinlang.org/docs/reference/data-classes.html[the `data` keyword] to make the compiler automatically derive the following members from all properties declared in the primary constructor: -* equals()/hashCode() pair -* toString() of the form "User(name=John, age=42)" -* componentN() functions corresponding to the properties in their order of declaration -* copy() function +* `equals()` and `hashCode()` +* `toString()` of the form `"User(name=John, age=42)"` +* `componentN()` functions that correspond to the properties in their order of declaration +* `copy()` function -This allows for easy changes to individual properties even if `Person` properties are read-only: +As the following example shows, this allows for easy changes to individual properties, even if `Person` properties are read-only: +==== [source,kotlin,indent=0] ---- data class Person(val name: String, val age: Int) @@ -436,31 +425,30 @@ This allows for easy changes to individual properties even if `Person` propertie val jack = Person(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) ---- +==== -Common persistence technologies such as JPA require a default constructor, preventing this +Common persistence technologies (such as JPA) require a default constructor, preventing this kind of design. Fortunately, there is now a workaround for this -https://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell["default constructor hell"] -since Kotlin provides a https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-jpa-compiler-plugin[kotlin-jpa] -plugin which generates synthetic no-arg constructor for classes annotated with JPA annotations. +https://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell["`default constructor hell`"], +since Kotlin provides a https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-jpa-compiler-plugin[`kotlin-jpa`] +plugin that generates synthetic no-arg constructor for classes annotated with JPA annotations. If you need to leverage this kind of mechanism for other persistence technologies, you can configure -the https://kotlinlang.org/docs/reference/compiler-plugins.html#how-to-use-no-arg-plugin[kotlin-noarg] +the https://kotlinlang.org/docs/reference/compiler-plugins.html#how-to-use-no-arg-plugin[`kotlin-noarg`] plugin. -[NOTE] -==== -As of the Kay release train, Spring Data supports Kotlin immutable class instances and -does not require the `kotlin-noarg` plugin if the module leverages Spring Data object -mappings (like with MongoDB, Redis, Cassandra, etc). -==== +NOTE: As of the Kay release train, Spring Data supports Kotlin immutable class instances and +does not require the `kotlin-noarg` plugin if the module uses Spring Data object +mappings (such as MongoDB, Redis, Cassandra, and others). -=== Injecting dependencies +=== Injecting Dependencies Our recommendation is to try and favor constructor injection with `val` read-only (and non-nullable when possible) -https://kotlinlang.org/docs/reference/properties.html[properties]. +https://kotlinlang.org/docs/reference/properties.html[properties], as the following example shows: +==== [source,kotlin,indent=0] ---- @Component @@ -469,17 +457,16 @@ https://kotlinlang.org/docs/reference/properties.html[properties]. private val solrClient: SolrClient ) ---- - -[NOTE] ==== -As of Spring Framework 4.3, classes with a single constructor have their + +NOTE: As of Spring Framework 4.3, classes with a single constructor have their parameters automatically autowired, that's why there is no need for an explicit `@Autowired constructor` in the example shown above. -==== -If one really needs to use field injection, use the `lateinit var` construct, -i.e., +If you really need to use field injection, you can use the `lateinit var` construct, +as the following example shows: +==== [source,kotlin,indent=0] ---- @Component @@ -492,20 +479,22 @@ i.e., lateinit var solrClient: SolrClient } ---- +==== -=== Injecting configuration properties +=== Injecting Configuration Properties -In Java, one can inject configuration properties using annotations like `@Value("${property}")`, -however in Kotlin `$` is a reserved character that is used for https://kotlinlang.org/docs/reference/idioms.html#string-interpolation[string interpolation]. +In Java, you can inject configuration properties by using annotations (such as `@Value("${property}")`). +However, in Kotlin, `$` is a reserved character that is used for https://kotlinlang.org/docs/reference/idioms.html#string-interpolation[string interpolation]. -Therefore, if one wishes to use the `@Value` annotation in Kotlin, the `$` -character will need to be escaped by writing `@Value("\${property}")`. +Therefore, if you wish to use the `@Value` annotation in Kotlin, you need to escape the `$` +character by writing `@Value("\${property}")`. -As an alternative, it is possible to customize the properties placeholder prefix by declaring +As an alternative, you can customize the properties placeholder prefix by declaring the following configuration beans: +==== [source,kotlin,indent=0] ---- @Bean @@ -513,10 +502,12 @@ the following configuration beans: setPlaceholderPrefix("%{") } ---- +==== -Existing code (like Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax, -can be customised with configuration beans, like as follows: +You can customize existing code (such as Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax, +with configuration beans, as the following example shows: +==== [source,kotlin,indent=0] ---- @Bean @@ -528,32 +519,31 @@ can be customised with configuration beans, like as follows: @Bean fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer() ---- - -[NOTE] ==== -If Spring Boot is being used, then + +NOTE: If you use Spring Boot, you can use https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties[`@ConfigurationProperties`] -instead of `@Value` annotations can be used, but currently this only works with `lateinit` or nullable `var` -properties (the former is recommended) since immutable classes initialized by +instead of `@Value` annotations. However, currently, this only works with `lateinit` or nullable `var` +properties (we recommended the former), since immutable classes initialized by constructors are not yet supported. See these issues about https://github.com/spring-projects/spring-boot/issues/8762[`@ConfigurationProperties` binding for immutable POJOs] and https://github.com/spring-projects/spring-boot/issues/1254[`@ConfigurationProperties` binding on interfaces] for more details. -==== -=== Annotation array attributes +=== Annotation Array Attributes -Kotlin annotations are mostly similar to Java ones, but array attributes - which are -extensively used in Spring - behave differently. As explained in +Kotlin annotations are mostly similar to Java annotations, but array attributes (which are +extensively used in Spring) behave differently. As explained in https://kotlinlang.org/docs/reference/annotations.html[Kotlin documentation] -unlike other attributes, the `value` attribute name can be omitted and -specified as a `vararg` parameter. +you can omit the `value` attribute name, unlike other attributes, and +specify it as a `vararg` parameter. -To understand what that means, let's take `@RequestMapping`, which is one -of the most widely used Spring annotations as an example. This Java annotation is declared as: +To understand what that means, consider `@RequestMapping` (which is one +of the most widely used Spring annotations) as an example. This Java annotation is declared as follows: +==== [source,java,indent=0] ---- public @interface RequestMapping { @@ -569,43 +559,48 @@ of the most widely used Spring annotations as an example. This Java annotation i // ... } ---- +==== The typical use case for `@RequestMapping` is to map a handler method to a specific path -and method. In Java, it is possible to specify a single value for the -annotation array attribute and it will be automatically converted to an array. +and method. In Java, you can specify a single value for the +annotation array attribute, and it is automatically converted to an array. -That's why one can write -`@RequestMapping(value = "/foo", method = RequestMethod.GET)` or -`@RequestMapping(path = "/foo", method = RequestMethod.GET)`. +That is why one can write +`@RequestMapping(value = "/toys", method = RequestMethod.GET)` or +`@RequestMapping(path = "/toys", method = RequestMethod.GET)`. -However, in Kotlin 1.2+, one will have to write `@RequestMapping("/foo", method = [RequestMethod.GET])` -or `@RequestMapping(path = ["/foo"], method = [RequestMethod.GET])` (square brackets need +However, in Kotlin 1.2+, you must write `@RequestMapping("/toys", method = [RequestMethod.GET])` +or `@RequestMapping(path = ["/toys"], method = [RequestMethod.GET])` (square brackets need to be specified with named array attributes). An alternative for this specific `method` attribute (the most common one) is to -use a shortcut annotation such as `@GetMapping` or `@PostMapping`, etc. +use a shortcut annotation, such as `@GetMapping`, `@PostMapping`, and others. -[NOTE] -==== -Reminder: If the `@RequestMapping` `method` attribute is not specified, +NOTE: Reminder: If the `@RequestMapping` `method` attribute is not specified, all HTTP methods will be matched, not only the `GET` one. -==== + === Testing +This section address testing with the combination of Kotlin and the Spring Framework. + -==== Per class lifecycle -Kotlin allows one to specify meaningful test function names between backticks, -and as of JUnit 5 Kotlin test classes can use the `@TestInstance(TestInstance.Lifecycle.PER_CLASS)` -annotation to enable a single instantiation of test classes which allows the use of `@BeforeAll` and `@AfterAll` +==== `PER_CLASS` Lifecycle + +Kotlin lets you specify meaningful test function names between backticks (\`). +As of JUnit 5, Kotlin test classes can use the `@TestInstance(TestInstance.Lifecycle.PER_CLASS)` +annotation to enable a single instantiation of test classes, which allows the use of `@BeforeAll` and `@AfterAll` annotations on non-static methods, which is a good fit for Kotlin. -It is now possible to change the default behavior to `PER_CLASS` thanks to a +You can now change the default behavior to `PER_CLASS` thanks to a `junit-platform.properties` file with a `junit.jupiter.testinstance.lifecycle.default = per_class` property. +The following example `@BeforeAll` and `@AfterAll` annotations on non-static methods: + +==== [source] ---- class IntegrationTests { @@ -635,12 +630,16 @@ class IntegrationTests { } } ---- +==== + -==== Specification-like tests +==== Specification-like Tests -It is possible to create specification-like tests with JUnit 5 and Kotlin. +You can create specification-like tests with JUnit 5 and Kotlin. +The following example shows how to do so: +==== [source] ---- class SpecificationLikeTests { @@ -664,13 +663,15 @@ class SpecificationLikeTests { } } ---- +==== + [[kotlin-webtestclient-issue]] -==== `WebTestClient` type inference issue in Kotlin +==== `WebTestClient` Type Inference Issue in Kotlin -Due to a https://youtrack.jetbrains.com/issue/KT-5464[type inference issue], make sure to -use Kotlin `expectBody` extension (like `.expectBody().isEqualTo("foo")`) since it +Due to a https://youtrack.jetbrains.com/issue/KT-5464[type inference issue], you must +use the Kotlin `expectBody` extension (such as `.expectBody().isEqualTo("toys")`), since it provides a workaround for the Kotlin issue with the Java API. See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue. @@ -678,41 +679,46 @@ See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue. [[kotlin-getting-started]] -== Getting started +== Getting Started +This section describes the fastest way to get started with a project that combines +Kotlin and the Spring Framework. -=== start.spring.io + +=== Using `start.spring.io` The easiest way to start a new Spring Framework 5 project in Kotlin is to create a new Spring Boot 2 project on https://start.spring.io/#!language=kotlin[start.spring.io]. -It is also possible to create a standalone WebFlux project as described in +You can also create a standalone WebFlux project, as described in https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way[this blog post]. -=== Choosing the web flavor +=== Choosing the Web Flavor -Spring Framework now comes with 2 different web stacks: <> and +Spring Framework now comes with two different web stacks: <> and <>. -Spring WebFlux is recommended if one wants to create applications that will deal with latency, -long-lived connections, streaming scenarios or simply if one wants to use the web functional +Spring WebFlux is recommended if you want to create applications that will deal with latency, +long-lived connections, o streaming scenarios or if you want to use the web functional Kotlin DSL. -For other use cases, especially if you are using blocking technologies like JPA, Spring +For other use cases, especially if you are using blocking technologies such as JPA, Spring MVC and its annotation-based programming model is a perfectly valid and fully supported choice. - [[kotlin-resources]] == Resources +We recommend the following resources for people learning how to build applications with +Kotlin and the Spring Framework: + * http://kotlinlang.org/docs/reference/[Kotlin language reference] * http://slack.kotlinlang.org/[Kotlin Slack] (with a dedicated #spring channel) -* https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow with `spring` and `kotlin` tags] +* https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow, with `spring` and `kotlin` tags] * https://try.kotlinlang.org/[Try Kotlin in your browser] * https://blog.jetbrains.com/kotlin/[Kotlin blog] * https://kotlin.link/[Awesome Kotlin] @@ -721,6 +727,8 @@ MVC and its annotation-based programming model is a perfectly valid and fully su === Tutorials +We recommend the following tutorials: + * https://spring.io/guides/tutorials/spring-boot-kotlin/[Building web applications with Spring Boot and Kotlin] * https://kotlinlang.org/docs/tutorials/spring-boot-restful.html[Creating a RESTful Web Service with Spring Boot] @@ -728,6 +736,8 @@ MVC and its annotation-based programming model is a perfectly valid and fully su === Blog posts +The following blog posts provide further details: + * https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin[Developing Spring Boot applications with Kotlin] * https://spring.io/blog/2016/03/20/a-geospatial-messenger-with-kotlin-spring-boot-and-postgresql[A Geospatial Messenger with Kotlin, Spring Boot and PostgreSQL] * https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0[Introducing Kotlin support in Spring Framework 5.0] @@ -737,44 +747,38 @@ MVC and its annotation-based programming model is a perfectly valid and fully su === Examples -* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: regular Spring Boot + Spring Data JPA project -* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2 + WebFlux + Reactive Spring Data MongoDB -* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: standalone WebFlux + functional bean definition DSL +The following Github projects offer examples that you can learn from and possibly even extend: + +* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: Regular Spring Boot and Spring Data JPA project +* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2, WebFlux, and Reactive Spring Data MongoDB +* https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional]: Standalone WebFlux and functional bean definition DSL * https://github.com/sdeleuze/spring-kotlin-fullstack[spring-kotlin-fullstack]: WebFlux Kotlin fullstack example with Kotlin2js for frontend instead of JavaScript or TypeScript * https://github.com/spring-petclinic/spring-petclinic-kotlin[spring-petclinic-kotlin]: Kotlin version of the Spring PetClinic Sample Application -* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: a step by step migration for Boot 1.0 + Java to Boot 2.0 + Kotlin +* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin === Issues -Here is a list of pending issues related to Spring + Kotlin support. - - -==== Spring Framework - -* https://jira.spring.io/browse/SPR-16057[Unable to use WebTestClient with mock server in Kotlin] -* https://jira.spring.io/browse/SPR-15942[Support null-safety at generics, varargs and array elements level] -* https://jira.spring.io/browse/SPR-15413[Add support for Kotlin coroutines] - - -==== Spring Boot - -* https://github.com/spring-projects/spring-boot/issues/8762[Allow `@ConfigurationProperties` binding for immutable POJOs] -* https://github.com/spring-projects/spring-boot/issues/1254[Allow `@ConfigurationProperties` binding on interfaces] -* https://github.com/spring-projects/spring-boot/issues/8115[Expose the functional bean registration API via `SpringApplication`] -* https://github.com/spring-projects/spring-boot/issues/10712[Add null-safety annotations on Spring Boot APIs] -* https://github.com/spring-projects/spring-boot/issues/9486[Use Kotlin's bom to provide dependency management for Kotlin] - - -==== Kotlin - -* https://youtrack.jetbrains.com/issue/KT-6380[Parent issue for Spring Framework support] -* https://youtrack.jetbrains.com/issue/KT-5464[Kotlin requires type inference where Java doesn't] -* https://github.com/Kotlin/KEEP/issues/79[Better generics null-safety support] -* https://youtrack.jetbrains.com/issue/KT-20283[Smart cast regression with open classes] -* https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function] -* https://youtrack.jetbrains.com/issue/KT-19592[Apply JSR 305 meta-annotations to generic type parameters] -* https://youtrack.jetbrains.com/issue/KT-18398[Provide a way for libraries to avoid mixing Kotlin 1.0 and 1.1 dependencies] -* https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables] -* https://youtrack.jetbrains.com/issue/KT-15467[Support all-open and no-arg compiler plugins in Kotlin Eclipse plugin] +The following list categorizes the pending issues related to Spring and Kotlin support: + +* Spring Framework +** https://jira.spring.io/browse/SPR-16057[Unable to use WebTestClient with mock server in Kotlin] +** https://jira.spring.io/browse/SPR-15942[Support null-safety at generics, varargs and array elements level] +** https://jira.spring.io/browse/SPR-15413[Add support for Kotlin coroutines] +* Spring Boot +** https://github.com/spring-projects/spring-boot/issues/8762[Allow `@ConfigurationProperties` binding for immutable POJOs] +** https://github.com/spring-projects/spring-boot/issues/1254[Allow `@ConfigurationProperties` binding on interfaces] +** https://github.com/spring-projects/spring-boot/issues/8115[Expose the functional bean registration API via `SpringApplication`] +** https://github.com/spring-projects/spring-boot/issues/10712[Add null-safety annotations on Spring Boot APIs] +** https://github.com/spring-projects/spring-boot/issues/9486[Use Kotlin's bom to provide dependency management for Kotlin] +* Kotlin +** https://youtrack.jetbrains.com/issue/KT-6380[Parent issue for Spring Framework support] +** https://youtrack.jetbrains.com/issue/KT-5464[Kotlin requires type inference where Java doesn't] +** https://github.com/Kotlin/KEEP/issues/79[Better generics null-safety support] +** https://youtrack.jetbrains.com/issue/KT-20283[Smart cast regression with open classes] +** https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function] +** https://youtrack.jetbrains.com/issue/KT-19592[Apply JSR 305 meta-annotations to generic type parameters] +** https://youtrack.jetbrains.com/issue/KT-18398[Provide a way for libraries to avoid mixing Kotlin 1.0 and 1.1 dependencies] +** https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables] +** https://youtrack.jetbrains.com/issue/KT-15467[Support all-open and no-arg compiler plugins in Kotlin Eclipse plugin] diff --git a/src/docs/asciidoc/web/webflux-webclient.adoc b/src/docs/asciidoc/web/webflux-webclient.adoc index c324e4a556..37435a7bd4 100644 --- a/src/docs/asciidoc/web/webflux-webclient.adoc +++ b/src/docs/asciidoc/web/webflux-webclient.adoc @@ -230,15 +230,14 @@ shows: }; ClientHttpConnector connector = - new JettyClientHttpConnector(resourceFactory(), customizer); <2> + new JettyClientHttpConnector(resourceFactory(), customizer); // <1> - return WebClient.builder().clientConnector(connector).build(); <3> + return WebClient.builder().clientConnector(connector).build(); // <2> } ---- -<1> Create resource factory for shared resources. -<2> Use the `JettyClientHttpConnector` constructor with resource factory. -<3> Plug the connector into the `WebClient.Builder`. +<1> Use the `JettyClientHttpConnector` constructor with resource factory. +<2> Plug the connector into the `WebClient.Builder`. ==== diff --git a/src/docs/asciidoc/web/webflux.adoc b/src/docs/asciidoc/web/webflux.adoc index 80542f3b6f..ce4b7681a2 100644 --- a/src/docs/asciidoc/web/webflux.adoc +++ b/src/docs/asciidoc/web/webflux.adoc @@ -74,7 +74,7 @@ If a publisher cannot slow down, it has to decide whether to buffer, drop, or fa [[webflux-reactive-api]] -=== Reactive API +== Reactive API Reactive Streams plays an important role for interoperability. It is of interest to libraries and infrastructure components but less useful as an application API, because it is too @@ -103,7 +103,7 @@ of RxJava or another reactive library. See <> for mo [[webflux-programming-models]] -=== Programming Models +== Programming Models The `spring-web` module contains the reactive foundation that underlies Spring WebFlux, including HTTP abstractions, Reactive Streams <> for supported @@ -125,7 +125,7 @@ annotations and being called back. [[webflux-framework-choice]] -=== Applicability +== Applicability Spring MVC or WebFlux? @@ -181,7 +181,7 @@ unsure what benefits to look for, start by learning about how non-blocking I/O w [[webflux-server-choice]] -=== Servers +== Servers Spring WebFlux is supported on Tomcat, Jetty, Servlet 3.1+ containers, as well as on non-Servlet runtimes such as Netty and Undertow. All servers are adapted to a low-level, @@ -209,7 +209,7 @@ For Undertow, Spring WebFlux uses Undertow APIs directly without the Servlet API [[webflux-performance]] -=== Performance versus Scale +== Performance versus Scale Performance has many characteristics and meanings. Reactive and non-blocking generally do not make applications run faster. They can, in some cases, (for example, if using the @@ -226,7 +226,7 @@ dramatic. [[webflux-concurrency-model]] -=== Concurrency Model +== Concurrency Model Both Spring MVC and Spring WebFlux support annotated controllers, but there is a key difference in the concurrency model and the default assumptions for blocking and threads.