From 9a3cb628af3c5e674a6a29fbbe01a85032d73709 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 25 Nov 2022 17:33:07 +0100 Subject: [PATCH] Split integration chapter in smaller documents This commit splits the integration chapter of the reference documentation in smaller documents for easier maintenance. --- .../src/docs/asciidoc/integration.adoc | 5724 +---------------- .../src/docs/asciidoc/integration/cache.adoc | 1070 +++ .../src/docs/asciidoc/integration/email.adoc | 302 + .../src/docs/asciidoc/integration/jms.adoc | 1472 +++++ .../src/docs/asciidoc/integration/jmx.adoc | 1375 ++++ .../asciidoc/integration/rest-clients.adoc | 517 ++ .../docs/asciidoc/integration/scheduling.adoc | 967 +++ 7 files changed, 5709 insertions(+), 5718 deletions(-) create mode 100644 framework-docs/src/docs/asciidoc/integration/cache.adoc create mode 100644 framework-docs/src/docs/asciidoc/integration/email.adoc create mode 100644 framework-docs/src/docs/asciidoc/integration/jms.adoc create mode 100644 framework-docs/src/docs/asciidoc/integration/jmx.adoc create mode 100644 framework-docs/src/docs/asciidoc/integration/rest-clients.adoc create mode 100644 framework-docs/src/docs/asciidoc/integration/scheduling.adoc diff --git a/framework-docs/src/docs/asciidoc/integration.adoc b/framework-docs/src/docs/asciidoc/integration.adoc index 4574c8d2d4..c28f341699 100644 --- a/framework-docs/src/docs/asciidoc/integration.adoc +++ b/framework-docs/src/docs/asciidoc/integration.adoc @@ -6,5728 +6,16 @@ include::page-layout.adoc[] This part of the reference documentation covers Spring Framework's integration with a number of technologies. +include::integration/rest-clients.adoc[leveloffset=+1] -[[rest-client-access]] -== REST Clients +include::integration/jms.adoc[leveloffset=+1] -The Spring Framework provides the following choices for making calls to REST endpoints: - -* <> - non-blocking, reactive client w fluent API. -* <> - synchronous client with template method API. -* <> - annotated interface with generated, dynamic proxy implementation. - - -[[rest-webclient]] -=== `WebClient` - -`WebClient` is a non-blocking, reactive client to perform HTTP requests. It was -introduced in 5.0 and offers an alternative to the `RestTemplate`, with support for -synchronous, asynchronous, and streaming scenarios. - -`WebClient` supports the following: - -* Non-blocking I/O. -* Reactive Streams back pressure. -* High concurrency with fewer hardware resources. -* Functional-style, fluent API that takes advantage of Java 8 lambdas. -* Synchronous and asynchronous interactions. -* Streaming up to or streaming down from a server. - -See <> for more details. - - - - -[[rest-resttemplate]] -=== `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 -overloaded methods: - -NOTE: `RestTemplate` is in maintenance mode, with only requests for minor -changes and bugs to be accepted. Please, consider using the -<> instead. - -[[rest-overview-of-resttemplate-methods-tbl]] -.RestTemplate methods -[cols="1,3"] -|=== -| Method group | Description - -| `getForObject` -| Retrieves a representation via GET. - -| `getForEntity` -| Retrieves a `ResponseEntity` (that is, status, headers, and body) by using GET. - -| `headForHeaders` -| Retrieves all headers for a resource by using HEAD. - -| `postForLocation` -| Creates a new resource by using POST and returns the `Location` header from the response. - -| `postForObject` -| Creates a new resource by using POST and returns the representation from the response. - -| `postForEntity` -| Creates a new resource by using POST and returns the representation from the response. - -| `put` -| Creates or updates a resource by using PUT. - -| `patchForObject` -| Updates a resource by using PATCH and returns the representation from the response. -Note that the JDK `HttpURLConnection` does not support `PATCH`, but Apache -HttpComponents and others do. - -| `delete` -| Deletes the resources at the specified URI by using DELETE. - -| `optionsForAllow` -| Retrieves allowed HTTP methods for a resource by using ALLOW. - -| `exchange` -| 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 through callback interfaces. - -|=== - -[[rest-resttemplate-create]] -==== Initialization - -The default constructor uses `java.net.HttpURLConnection` to perform requests. You can -switch to a different HTTP library with an implementation of `ClientHttpRequestFactory`. -There is built-in support for the following: - -* Apache HttpComponents -* Netty -* OkHttp - -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 -- for example, for credentials, connection pooling, and other details. - -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 accept a URI template and URI template variables, -either as a `String` variable argument, or as `Map`. - -The following example uses a `String` variable argument: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - String result = restTemplate.getForObject( - "https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21"); ----- - -The following example uses a `Map`: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - Map vars = Collections.singletonMap("hotel", "42"); - - String result = restTemplate.getForObject( - "https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); ----- - -Keep in mind URI templates are automatically encoded, as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - restTemplate.getForObject("https://example.com/hotel list", String.class); - - // Results in request to "https://example.com/hotel%20list" ----- - -You can use the `uriTemplateHandler` property of `RestTemplate` to customize how URIs -are 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 - -You can use the `exchange()` methods to specify request headers, as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - String uriTemplate = "https://example.com/hotels/{hotel}"; - URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42); - - RequestEntity requestEntity = RequestEntity.get(uri) - .header("MyRequestHeader", "MyValue") - .build(); - - ResponseEntity response = template.exchange(requestEntity, String.class); - - String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); - String body = response.getBody(); ----- - -You can obtain response headers through many `RestTemplate` method variants that return -`ResponseEntity`. - -[[rest-template-body]] -==== Body - -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, as the following example shows: - ----- -URI location = template.postForLocation("https://example.com/people", person); ----- - -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`, as the following example shows: - ----- -Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42); ----- - -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. - -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]#<># - -The `spring-web` module contains the `HttpMessageConverter` contract for reading and -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, by default, registered with the `RestTemplate` on the client side and with -`RequestMappingHandlerAdapter` on the server side (see -<>). - -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 -[cols="1,3"] -|=== -| MessageConverter | Description - -| `StringHttpMessageConverter` -| 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 -`application/x-www-form-urlencoded` media type. Form data is read from and written into a -`MultiValueMap`. The converter can also write (but not read) multipart -data read from a `MultiValueMap`. By default, `multipart/form-data` is -supported. As of Spring Framework 5.2, additional multipart subtypes can be supported for -writing form data. Consult the javadoc for `FormHttpMessageConverter` for further details. - -| `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`. You can override this -by setting the `supportedMediaTypes` property and overriding `getContentType(byte[])`. - -| `MarshallingHttpMessageConverter` -| 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. 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 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 by using -https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's -`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`. - -| `BufferedImageHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write -`java.awt.image.BufferedImage` from the HTTP request and response. This converter reads -and writes the media type supported by the Java I/O API. - -|=== - -[[rest-template-jsonview]] -==== Jackson JSON Views - -You can specify a https://www.baeldung.com/jackson-json-view-annotation[Jackson JSON View] -to serialize only a subset of the object properties, as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23")); - value.setSerializationView(User.WithoutPasswordView.class); - - RequestEntity requestEntity = - RequestEntity.post(new URI("https://example.com/user")).body(value); - - ResponseEntity response = template.exchange(requestEntity, String.class); ----- - -[[rest-template-multipart]] -==== Multipart - -To send multipart data, you need to provide a `MultiValueMap` whose values -may be an `Object` for part content, a `Resource` for a file part, or an `HttpEntity` for -part content with headers. For example: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - MultiValueMap parts = new LinkedMultiValueMap<>(); - - parts.add("fieldPart", "fieldValue"); - parts.add("filePart", new FileSystemResource("...logo.png")); - parts.add("jsonPart", new Person("Jason")); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_XML); - parts.add("xmlPart", new HttpEntity<>(myBean, headers)); ----- - -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` with an `HttpEntity` wrapper. - -Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as show below: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - MultiValueMap parts = ...; - template.postForObject("https://example.com/upload", parts, Void.class); ----- - -If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set -to `multipart/form-data` by the `FormHttpMessageConverter`. If the `MultiValueMap` has -`String` values the `Content-Type` is defaulted to `application/x-www-form-urlencoded`. -If necessary the `Content-Type` may also be set explicitly. - - -[[rest-http-interface]] -=== HTTP Interface - -The Spring Framework lets you define an HTTP service as a Java interface with annotated -methods for HTTP exchanges. You can then generate a proxy that implements this interface -and performs the exchanges. This helps to simplify HTTP remote access which often -involves a facade that wraps the details of using the underlying HTTP client. - -One, declare an interface with `@HttpExchange` methods: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - interface RepositoryService { - - @GetExchange("/repos/{owner}/{repo}") - Repository getRepository(@PathVariable String owner, @PathVariable String repo); - - // more HTTP exchange methods... - - } ----- - -Two, create a proxy that will perform the declared HTTP exchanges: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build(); - HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build(); - - RepositoryService service = factory.createClient(RepositoryService.class); ----- - -`@HttpExchange` is supported at the type level where it applies to all methods: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json") - interface RepositoryService { - - @GetExchange - Repository getRepository(@PathVariable String owner, @PathVariable String repo); - - @PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - void updateRepository(@PathVariable String owner, @PathVariable String repo, - @RequestParam String name, @RequestParam String description, @RequestParam String homepage); - - } ----- - - -[[rest-http-interface-method-parameters]] -==== Method Parameters - -Annotated, HTTP exchange methods support flexible method signatures with the following -method parameters: - -[cols="1,2", options="header"] -|=== -| Method argument | Description - -| `URI` -| Dynamically set the URL for the request, overriding the annotation's `url` attribute. - -| `HttpMethod` -| Dynamically set the HTTP method for the request, overriding the annotation's `method` attribute - -| `@RequestHeader` -| Add a request header or mutliple headers. The argument may be a `Map` or - `MultiValueMap` with multiple headers, a `Collection` of values, or an - individual value. Type conversion is supported for non-String values. - -| `@PathVariable` -| Add a variable for expand a placeholder in the request URL. The argument may be a - `Map` with multiple variables, or an individual value. Type conversion - is supported for non-String values. - -| `@RequestBody` -| Provide the body of the request either as an Object to be serialized, or a - Reactive Streams `Publisher` such as `Mono`, `Flux`, or any other async type supported - through the configured `ReactiveAdapterRegistry`. - -| `@RequestParam` -| Add a request parameter or mutliple parameters. The argument may be a `Map` - or `MultiValueMap` with multiple parameters, a `Collection` of values, or - an individual value. Type conversion is supported for non-String values. - - When `"content-type"` is set to `"application/x-www-form-urlencoded"`, request - parameters are encoded in the request body. Otherwise, they are added as URL query - parameters. - -| `@RequestPart` -| Add a request part, which may be a String (form field), `Resource` (file part), - Object (entity to be encoded, e.g. as JSON), `HttpEntity` (part content and headers), - a Spring `Part`, or Reactive Streams `Publisher` of any of the above. - -| `@CookieValue` -| Add a cookie or mutliple cookies. The argument may be a `Map` or - `MultiValueMap` with multiple cookies, a `Collection` of values, or an - individual value. Type conversion is supported for non-String values. - -|=== - - -[[rest-http-interface-return-values]] -==== Return Values - -Annotated, HTTP exchange methods support the following return values: - -[cols="1,2", options="header"] -|=== -| Method return value | Description - -| `void`, `Mono` -| Perform the given request, and release the response content, if any. - -| `HttpHeaders`, `Mono` -| Perform the given request, release the response content, if any, and return the - response headers. - -| ``, `Mono` -| Perform the given request and decode the response content to the declared return type. - -| ``, `Flux` -| Perform the given request and decode the response content to a stream of the declared - element type. - -| `ResponseEntity`, `Mono>` -| Perform the given request, and release the response content, if any, and return a - `ResponseEntity` with the status and headers. - -| `ResponseEntity`, `Mono>` -| Perform the given request, decode the response content to the declared return type, and - return a `ResponseEntity` with the status, headers, and the decoded body. - -| `Mono>` -| Perform the given request, decode the response content to a stream of the declared - element type, and return a `ResponseEntity` with the status, headers, and the decoded - response body stream. - -|=== - -TIP: You can also use any other async or reactive types registered in the -`ReactiveAdapterRegistry`. - - -[[rest-http-interface-exceptions]] -==== Exception Handling - -By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status -codes. To customize this, you can register a response status handler that applies to all -responses performed through the client: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - WebClient webClient = WebClient.builder() - .defaultStatusHandler(HttpStatusCode::isError, resp -> ...) - .build(); - - WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient); - HttpServiceProxyFactory factory = HttpServiceProxyFactory - .builder(clientAdapter).build(); ----- - -For more details and options, such as suppressing error status codes, see the Javadoc of -`defaultStatusHandler` in `WebClient.Builder`. - - - - -[[jms]] -== JMS (Java Message Service) - -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 Jakarta EE's -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 `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 sending messages, -consuming messages synchronously, and exposing the JMS session and message producer to -the user. - -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 any provider-specific subclasses -of the checked `jakarta.jms.JMSException` exist, this exception is wrapped in the -unchecked `UncategorizedJmsException`. - -The `org.springframework.jms.support.converter` package provides a `MessageConverter` -abstraction to convert between Java objects and JMS messages. - -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 `org.springframework.jms.annotation` package provides the necessary infrastructure -to support annotation-driven listener endpoints by using `@JmsListener`. - -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 `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 -resource into Spring's transaction management mechanisms. - -[NOTE] -==== -As of Spring Framework 5, Spring's JMS package fully supports JMS 2.0 and requires the -JMS 2.0 API to be present at runtime. We recommend the use of a JMS 2.0 compatible provider. - -If you happen to use an older message broker in your system, you may try upgrading to a -JMS 2.0 compatible driver for your existing broker generation. Alternatively, you may also -try to run against a JMS 1.1 based driver, simply putting the JMS 2.0 API jar on the -classpath but only using JMS 1.1 compatible API against your driver. Spring's JMS support -adheres to JMS 1.1 conventions by default, so with corresponding configuration it does -support such a scenario. However, please consider this for transition scenarios only. -==== - - - -[[jms-using]] -=== Using Spring JMS - -This section describes how to use Spring's JMS components. - - -[[jms-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 -synchronously receiving messages. - -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 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 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 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 -for sending a message and waiting for a reply on a temporary queue that is created as part of -the operation. - -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. - -As of Spring Framework 4.1, `JmsMessagingTemplate` is built on top of `JmsTemplate` -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]] -==== Connections - -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. - -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 -of connections and sessions. In order to use this implementation, Jakarta EE containers -typically require that you declare a JMS connection factory as a `resource-ref` inside -the EJB or servlet deployment descriptors. To ensure the use of these features with the -`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: - -[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`. - -[[jms-connection-factory]] -===== Using `SingleConnectionFactory` - -Spring provides an implementation of the `ConnectionFactory` interface, -`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]] -===== Using `CachingConnectionFactory` - -The `CachingConnectionFactory` extends the functionality of `SingleConnectionFactory` -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, -noLocal delivery flag, and the durable subscription name (if creating durable consumers). - -[NOTE] -==== -MessageProducers and MessageConsumers for temporary queues and topics -(TemporaryQueue/TemporaryTopic) will never be cached. Unfortunately, WebLogic JMS happens -to implement the temporary queue/topic interfaces on its regular destination implementation, -mis-indicating that none of its destinations can be cached. Please use a different connection -pool/cache on WebLogic, or customize `CachingConnectionFactory` for WebLogic purposes. -==== - - -[[jms-destinations]] -==== Destination Management - -Destinations, as `ConnectionFactory` instances, are JMS administered objects that you can store -and retrieve 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 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 that implements the -`DestinationResolver` interface. `DynamicDestinationResolver` is the default -implementation used by `JmsTemplate` and accommodates resolving dynamic destinations. A -`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 -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 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. -However, a simple implementation choice that is sometimes made by vendors is to -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`, 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 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.) 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 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 specialized feature set. - -* <> -* <> - -[[jms-mdp-simple]] -===== 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 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 Jakarta EE's JMS restrictions. - -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 `Session` instances and, therefore, does not include any other -`Session` operations (such as sending response messages) in the transaction protocol. - -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]] -===== Using `DefaultMessageListenerContainer` - -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`. 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 participation in externally managed -transactions), and compatibility with Jakarta EE environments. - -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 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 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`) 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.). - -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 - -Spring provides a `JmsTransactionManager` that manages transactions for a single JMS -`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 Jakarta 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` 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` -class. - -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 Jakarta 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 -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 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`. - - - -[[jms-sending]] -=== Sending a Message - -The `JmsTemplate` contains many convenience methods to send a message. Send -methods specify the destination by using a `jakarta.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"] ----- - import jakarta.jms.ConnectionFactory; - import jakarta.jms.JMSException; - import jakarta.jms.Message; - import jakarta.jms.Queue; - import jakarta.jms.Session; - - import org.springframework.jms.core.MessageCreator; - import org.springframework.jms.core.JmsTemplate; - - public class JmsQueueSender { - - private JmsTemplate jmsTemplate; - private Queue queue; - - public void setConnectionFactory(ConnectionFactory cf) { - this.jmsTemplate = new JmsTemplate(cf); - } - - public void setQueue(Queue queue) { - this.queue = queue; - } - - public void simpleSend() { - this.jmsTemplate.send(this.queue, new MessageCreator() { - public Message createMessage(Session session) throws JMSException { - return session.createTextMessage("hello queue world"); - } - }); - } - } ----- - -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 -deriving from Spring's `JmsGatewaySupport` convenience base class, which provides -pre-built bean properties for JMS configuration. - -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`. - -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 - -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()` 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 -between `String` and `TextMessage`, `byte[]` and `BytesMessage`, 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 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 -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 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 -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"] ----- - public void sendWithConversion() { - Map map = new HashMap(); - map.put("Name", "Mark"); - map.put("Age", new Integer(47)); - jmsTemplate.convertAndSend("testQueue", map, new MessagePostProcessor() { - public Message postProcessMessage(Message message) throws JMSException { - message.setIntProperty("AccountID", 1234); - message.setJMSCorrelationID("123-00001"); - return message; - } - }); - } ----- - -This results in a message of the following form: - -[literal] -[subs="verbatim,quotes"] ----- -MapMessage={ - Header={ - ... standard headers ... - CorrelationID={123-00001} - } - Properties={ - AccountID={Integer:1234} - } - Fields={ - Name={String:Mark} - Age={Integer:47} - } -} ----- - - -[[jms-callbacks]] -==== Using `SessionCallback` and `ProducerCallback` - -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` run -these callback methods. - - - -[[jms-receiving]] -=== Receiving a Message - -This describes how to receive messages with JMS in Spring. - - -[[jms-receiving-sync]] -==== Synchronous Reception - -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 `receiveTimeout` property specifies how long -the receiver should wait before giving up waiting for a message. - - -[[jms-receiving-async]] -==== Asynchronous reception: Message-Driven POJOs - -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 <> 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 -<>) on an MDP is that it must implement -the `jakarta.jms.MessageListener` interface. Note that, if your POJO receives messages -on multiple threads, it is important to ensure that your implementation is thread-safe. - -The following example shows a simple implementation of an MDP: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - import jakarta.jms.JMSException; - import jakarta.jms.Message; - import jakarta.jms.MessageListener; - import jakarta.jms.TextMessage; - - public class ExampleListener implements MessageListener { - - public void onMessage(Message message) { - if (message instanceof TextMessage textMessage) { - try { - System.out.println(textMessage.getText()); - } - catch (JMSException ex) { - throw new RuntimeException(ex); - } - } - else { - throw new IllegalArgumentException("Message must be of type TextMessage"); - } - } - } ----- - -Once you have implemented your `MessageListener`, it is time to create a message listener -container. - -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"] ----- - - - - - - - - - ----- - -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]] -==== Using the `SessionAwareMessageListener` Interface - -The `SessionAwareMessageListener` interface is a Spring-specific interface that provides -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"] ----- - package org.springframework.jms.listener; - - public interface SessionAwareMessageListener { - - 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 (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 -`SessionAwareMessageListener` come with the caveat that they are then tied to Spring -through the interface. The choice of whether or not to use it is left entirely up to you -as an application developer or architect. - -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 thrown exceptions. - - -[[jms-receiving-async-message-listener-adapter]] -==== Using `MessageListenerAdapter` - -The `MessageListenerAdapter` class is the final component in Spring's asynchronous -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: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface MessageDelegate { - - void handleMessage(String message); - - void handleMessage(Map message); - - void handleMessage(byte[] message); - - void handleMessage(Serializable message); - } ----- - -Notice that, although the interface extends neither the `MessageListener` nor the -`SessionAwareMessageListener` interface, you can still use it as an 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"] ----- - public class DefaultMessageDelegate implements MessageDelegate { - // implementation elided for clarity... - } ----- - -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"] ----- - - - - - - - - - - - - - ----- - -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 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 `TextMessageDelegate` interface: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface TextMessageDelegate { - - void receive(TextMessage message); - } ----- - -The following listing shows a class that implements the `TextMessageDelegate` interface: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public class DefaultTextMessageDelegate implements TextMessageDelegate { - // implementation elided for clarity... - } ----- - -The configuration of the attendant `MessageListenerAdapter` would then be as follows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - ----- - -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 following interface and class: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface ResponsiveTextMessageDelegate { - - // notice the return type... - String receive(TextMessage message); - } ----- - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate { - // implementation elided for clarity... - } ----- - -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 - -Invoking a message listener within a transaction requires only reconfiguration of the -listener container. - -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 (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"] ----- - - - - - - ----- - -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 want -to configure a `JtaTransactionManager` (which, by default, delegates to the Jakarta 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 -Jakarta 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 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"] ----- - - - - - <1> - ----- -<1> Our transaction manager. - - - -[[jms-jca-message-endpoint-manager]] -=== Support for JCA Message Endpoints - -Beginning with version 2.5, Spring also provides support for a JCA-based -`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 provide -Spring's generic `JmsActivationSpecConfig`, as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -Alternatively, you can set up a `JmsMessageEndpointManager` with a given -`ActivationSpec` object. The `ActivationSpec` object may also come from a JNDI lookup -(using ``). The following example shows how to do so: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - ----- - -Using Spring's `ResourceAdapterFactoryBean`, you can configure the target `ResourceAdapter` -locally, as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - ----- - -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 (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`. - -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 that is not tied to JMS: -`org.springframework.jca.endpoint.GenericMessageEndpointManager`. This component allows -for using any message listener type (such as a JMS `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 - -The easiest way to receive a message asynchronously is to use the annotated listener -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"] ----- - @Component - public class MyService { - - @JmsListener(destination = "myDestination") - public void processOrder(String data) { ... } - } ----- - -The idea of the preceding example is that, whenever a message is available on the -`jakarta.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, by using a `JmsListenerContainerFactory`. -Such a container is not registered against the application context but can be easily -located for management purposes by using the `JmsListenerEndpointRegistry` bean. - -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 - -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"] ----- - @Configuration - @EnableJms - public class AppConfig { - - @Bean - public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() { - DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); - factory.setConnectionFactory(connectionFactory()); - factory.setDestinationResolver(destinationResolver()); - factory.setSessionTransacted(true); - factory.setConcurrency("3-10"); - return factory; - } - } ----- - -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), you can invoke the `processOrder` -method with a core poll size of three threads and a maximum pool size of ten threads. - -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 <>, you can use the `` -element, as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - ----- - - -[[jms-annotated-programmatic-registration]] -==== Programmatic Endpoint Registration - -`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"] ----- - @Configuration - @EnableJms - public class AppConfig implements JmsListenerConfigurer { - - @Override - public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { - SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint(); - endpoint.setId("myJmsEndpoint"); - endpoint.setDestination("anotherQueue"); - endpoint.setMessageListener(message -> { - // processing - }); - registrar.registerEndpoint(endpoint); - } - } ----- - -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`. - - -[[jms-annotated-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. In the following example, we rewrite it to inject the `Order` with -a custom header: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Component - public class MyService { - - @JmsListener(destination = "myDestination") - public void processOrder(Order order, @Header("order_type") String orderType) { - ... - } - } ----- - -The main elements you can inject in JMS listener endpoints are as follows: - -* The raw `jakarta.jms.Message` or any of its subclasses (provided that it - matches the incoming message type). -* The `jakarta.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. -* 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 (`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. 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 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 the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Configuration - @EnableJms - public class AppConfig implements JmsListenerConfigurer { - - @Override - public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { - registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory()); - } - - @Bean - public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() { - DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); - factory.setValidator(myValidator()); - return factory; - } - } ----- - - -[[jms-annotated-response]] -==== Response Management - -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 `jakarta.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. You can now set that default destination by using the `@SendTo` annotation of the -messaging abstraction. - -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"] ----- - @JmsListener(destination = "myDestination") - @SendTo("status") - public OrderStatus processOrder(Order order) { - // order processing - return status; - } ----- - -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 can return a -`Message` instead, with a method similar to the following: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @JmsListener(destination = "myDestination") - @SendTo("status") - public Message processOrder(Order order) { - // order processing - return MessageBuilder - .withPayload(status) - .setHeader("code", 1234) - .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. We can rewrite the previous -example as follows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @JmsListener(destination = "myDestination") - public JmsResponse> processOrder(Order order) { - // order processing - Message response = MessageBuilder - .withPayload(status) - .setHeader("code", 1234) - .build(); - 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, -as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Configuration - @EnableJms - public class AppConfig { - - @Bean - public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() { - DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); - factory.setConnectionFactory(connectionFactory()); - QosSettings replyQosSettings = new QosSettings(); - replyQosSettings.setPriority(2); - replyQosSettings.setTimeToLive(10000); - factory.setReplyQosSettings(replyQosSettings); - return factory; - } - } ----- - - - -[[jms-namespace]] -=== JMS Namespace Support - -Spring provides an XML namespace for simplifying JMS configuration. To use the JMS -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 https://www.springframework.org/schema/beans/spring-beans.xsd - http://www.springframework.org/schema/jms https://www.springframework.org/schema/jms/spring-jms.xsd"> - - - - ----- -<1> Referencing the JMS schema. - - -The namespace consists of three top-level elements: ``, `` -and ``. `` enables the use of <>. `` and `` -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"] ----- - - - - - - - ----- - -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 -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 -[cols="1,6"] -|=== -| Attribute | Description - -| `id` -| A bean name for the hosting listener container. If not specified, a bean name is - automatically generated. - -| `destination` (required) -| The destination name for this listener, resolved through the `DestinationResolver` - strategy. - -| `ref` (required) -| The bean name of the handler object. - -| `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 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` -| The name of the durable subscription, if any. - -| `selector` -| An optional message selector for this listener. - -| `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. By using -these attributes, you can define highly-customized listener containers while -still benefiting from the convenience of the namespace. - -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"] ----- - - - - - - - ----- - -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]] -.Attributes of the JMS element -[cols="1,6"] -|=== -| Attribute | Description - -| `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 a fully qualified class name. - The default is Spring's standard `DefaultMessageListenerContainer` or - `SimpleMessageListenerContainer`, according to the `container-type` attribute. - -| `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. - -| `connection-factory` -| A reference to the JMS `ConnectionFactory` bean (the default bean name is - `connectionFactory`). - -| `task-executor` -| A reference to the Spring `TaskExecutor` for the JMS listener invokers. - -| `destination-resolver` -| A reference to the `DestinationResolver` strategy for resolving JMS `Destination` instances. - -| `message-converter` -| A reference to the `MessageConverter` strategy for converting JMS Messages to listener - method arguments. The default is a `SimpleMessageConverter`. - -| `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 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` or `topic`. The default is the value of the - `destination-type` attribute. - -| `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 is effectively `consumer`, unless - an external transaction manager has been specified -- in which case, the effective - default will be `none` (assuming Jakarta 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, you can specify - the `transaction-manager` attribute, described later in table. The default is `auto`. - -| `transaction-manager` -| A reference to an external `PlatformTransactionManager` (typically an XA-based - 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` -| The maximum number of messages to load into a single session. Note that raising this - number might lead to starvation of concurrent consumers. - -| `receive-timeout` -| The timeout (in milliseconds) to use for receive calls. The default is `1000` (one - second). `-1` indicates no timeout. - -| `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 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 milliseconds (that is, five seconds). - -| `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 milliseconds - (that is, five seconds). - -| `phase` -| The lifecycle phase within which this container should start and stop. The lower the - 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, -as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - ----- - -The following table describes the available configuration options for the JCA variant: - -[[jms-namespace-jca-listener-container-tbl]] -.Attributes of the JMS element -[cols="1,6"] -|=== -| Attribute | Description - -| `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. - -| `resource-adapter` -| A reference to the JCA `ResourceAdapter` bean (the default bean name is - `resourceAdapter`). - -| `activation-spec-factory` -| A reference to the `JmsActivationSpecFactory`. The default is to autodetect the JMS - provider and its `ActivationSpec` class (see {api-spring-framework}/jms/listener/endpoint/DefaultJmsActivationSpecFactory.html[`DefaultJmsActivationSpecFactory`]). - -| `destination-resolver` -| A reference to the `DestinationResolver` strategy for resolving JMS `Destinations`. - -| `message-converter` -| A reference to the `MessageConverter` strategy for converting JMS Messages to listener - method arguments. The default is `SimpleMessageConverter`. - -| `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` or `topic`. The default is the value of the - `destination-type` attribute. - -| `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, you can specify - the `transaction-manager` attribute described later. The default is `auto`. - -| `transaction-manager` -| A reference to a Spring `JtaTransactionManager` or a - `jakarta.transaction.TransactionManager` for kicking off an XA transaction for each - incoming message. 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 only a - hint and is typically ignored at runtime when you use a JCA listener container. - The default is 1. - -| `prefetch` -| The maximum number of messages to load into a single session. Note that raising this - number might lead to starvation of concurrent consumers. -|=== - - - - -[[jmx]] -== JMX - -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 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. - -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 -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 - -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"] ----- - package org.springframework.jmx; - - public class JmxTestBean implements IJmxTestBean { - - private String name; - private int age; - private boolean isSuperman; - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public int add(int x, int y) { - return x + y; - } - - public void dontExposeMe() { - throw new RuntimeException(); - } - } ----- - -To expose the properties and methods of this bean as attributes and operations of an -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"] ----- - - - - - - - - - - - - - - ----- - -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. 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 (except those inherited from the -`Object` class) are exposed as operations. - -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 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 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 -`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` instance's `server` property to the `MBeanServer` value returned by an -`MBeanServerFactoryBean`, as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - ----- - -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. - - -[[jmx-mbean-server]] -==== Reusing an Existing `MBeanServer` - -If no server is specified, the `MBeanExporter` tries to automatically detect a running -`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"] ----- - - - - - - - - - - ... - - ----- - -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"] ----- - - - - - - - - - - - ----- - - -[[jmx-exporting-lazy]] -==== Lazily Initialized MBeans - -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 - -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. 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"] ----- - - - - - ----- - -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 <>. - - -[[jmx-exporting-registration-behavior]] -==== Controlling the Registration Behavior - -Consider the scenario where a Spring `MBeanExporter` attempts to register 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`). - -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`. -The following table summarizes these registration behaviors: - -[[jmx-registration-behaviors]] -.Registration Behaviors -[cols="1,4"] -|=== -| Registration behavior | Explanation - -| `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 is not - registered, and an `InstanceAlreadyExistsException` is thrown. The existing - `MBean` is unaffected. - -| `IGNORE_EXISTING` -| If an `MBean` instance has already been registered under the same `ObjectName`, the - `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`. - -| `REPLACE_EXISTING` -| If an `MBean` instance has already been registered under the same `ObjectName`, 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 values in the preceding table are defined as enums on the `RegistrationPolicy` class. -If you want to change the default registration behavior, you need to set the value of the -`registrationPolicy` property on your `MBeanExporter` definition to one of those -values. - -The following example shows how to change from the default registration -behavior to the `REPLACE_EXISTING` behavior: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - ----- - - - -[[jmx-interface]] -=== Controlling the Management Interface of Your Beans - -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]] -==== 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 exposed. -The default implementation, -`org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler`, -defines a management interface that exposes all public properties and methods -(as you 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 - -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 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. 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. - -NOTE: A `ManagedResource`-annotated bean must be public, as must the methods exposing -an operation or an attribute. - -The following example shows the annotated version of the `JmxTestBean` class that we -used in <>: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - package org.springframework.jmx; - - import org.springframework.jmx.export.annotation.ManagedResource; - import org.springframework.jmx.export.annotation.ManagedOperation; - import org.springframework.jmx.export.annotation.ManagedAttribute; - - @ManagedResource( - objectName="bean:name=testBean4", - description="My Managed Bean", - log=true, - logFile="jmx.log", - currencyTimeLimit=15, - persistPolicy="OnUpdate", - persistPeriod=200, - persistLocation="foo", - persistName="bar") - public class AnnotationTestBean implements IJmxTestBean { - - private String name; - private int age; - - @ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15) - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - @ManagedAttribute(description="The Name Attribute", - currencyTimeLimit=20, - defaultValue="bar", - persistPolicy="OnUpdate") - public void setName(String name) { - this.name = name; - } - - @ManagedAttribute(defaultValue="foo", persistPeriod=300) - public String getName() { - return name; - } - - @ManagedOperation(description="Add two numbers") - @ManagedOperationParameters({ - @ManagedOperationParameter(name = "x", description = "The first number"), - @ManagedOperationParameter(name = "y", description = "The second number")}) - public int add(int x, int y) { - return x + y; - } - - public void dontExposeMe() { - throw new RuntimeException(); - } - - } ----- - -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 <>. - -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, 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 following configuration shows how you can configure the `MBeanExporter` to use the -`MetadataMBeanInfoAssembler`: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - - - - - ----- - -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 - -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. -| `@ManagedResource` -| Class - -| Mark a method as a JMX operation. -| `@ManagedOperation` -| Method - -| Mark a getter or setter as one half of a JMX attribute. -| `@ManagedAttribute` -| Method (only getters and setters) - -| Define descriptions for operation parameters. -| `@ManagedOperationParameter` and `@ManagedOperationParameters` -| Method -|=== - -The following table describes the configuration parameters that are available for use on these source-level -metadata types: - -[[jmx-metadata-parameters]] -.Source-level metadata parameters -[cols="1,3,1"] -|=== -| Parameter | Description | Applies to - -| `ObjectName` -| 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`, or `ManagedOperationParameter` - -| `currencyTimeLimit` -| Sets the value of the `currencyTimeLimit` descriptor field. -| `ManagedResource` or `ManagedAttribute` - -| `defaultValue` -| Sets the value of the `defaultValue` descriptor field. -| `ManagedAttribute` - -| `log` -| Sets the value of the `log` descriptor field. -| `ManagedResource` - -| `logFile` -| Sets the value of the `logFile` descriptor field. -| `ManagedResource` - -| `persistPolicy` -| Sets the value of the `persistPolicy` descriptor field. -| `ManagedResource` - -| `persistPeriod` -| Sets the value of the `persistPeriod` descriptor field. -| `ManagedResource` - -| `persistLocation` -| Sets the value of the `persistLocation` descriptor field. -| `ManagedResource` - -| `persistName` -| Sets the value of the `persistName` descriptor field. -| `ManagedResource` - -| `name` -| Sets the display name of an operation parameter. -| `ManagedOperationParameter` - -| `index` -| Sets the index of an operation parameter. -| `ManagedOperationParameter` -|=== - - -[[jmx-interface-autodetect]] -==== Using the `AutodetectCapableMBeanInfoAssembler` Interface - -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`, it is -allowed to "`vote`" on the inclusion of beans for exposure to JMX. - -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 similar to the following: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - ----- - -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 by Using Java Interfaces - -In addition to the `MetadataMBeanInfoAssembler`, Spring also includes the -`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, `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 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"] ----- - public interface IJmxTestBean { - - public int add(int x, int y); - - public long myOperation(); - - public int getAge(); - - public void setAge(int age); - - public void setName(String name); - - public String getName(); - - } ----- - -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"] ----- - - - - - - - - - - - - org.springframework.jmx.IJmxTestBean - - - - - - - - - - - ----- - -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 -interface. - -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 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, 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` - -`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"] ----- - - - - - - - - - - add,myOperation,getName,setName,getAge - - - - ----- - -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 `ObjectName` Instances for Your Beans - -Behind the scenes, the `MBeanExporter` delegates to an implementation 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` (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 `ObjectName` Instances from Properties - -You can configure your own `KeyNamingStrategy` instance and configure it to read -`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 following code shows a sample configuration for the `KeyNamingStrategy`: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - bean:name=testBean1 - - - - names1.properties,names2.properties - - - - ----- - -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 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, the bean key name is used as -the `ObjectName`. - - -[[jmx-naming-metadata]] -==== Using `MetadataNamingStrategy` - -`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"] ----- - - - - - - - - - - - - - - - - - - - - - - - ----- - -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 - -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, -as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Configuration - @EnableMBeanExport - public class AppConfig { - - } ----- - -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"] ----- - ----- - -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 `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"] ----- - @EnableMBeanExport(server="myMBeanServer", defaultDomain="myDomain") - @Configuration - ContextConfiguration { - - } ----- - -The following example shows the XML equivalent of the preceding annotation-based example: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - ----- - -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]] -=== 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 -connectors. - - -[[jmx-jsr160-server]] -==== Server-side Connectors - -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 -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, -the main open-source JMX implementation, MX4J, and the one provided with the JDK -do not support JMXMP. - -To specify another URL and register the `JMXConnectorServer` itself with the -`MBeanServer`, you can use the `serviceUrl` and `ObjectName` properties, respectively, -as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - ----- - -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"] ----- - - - - - - - - - - - ----- - -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. - - -[[jmx-jsr160-client]] -==== Client-side Connectors - -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"] ----- - - - ----- - - -[[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 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 such as SOAP or Hessian over simple HTTP or SSL and others, -as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - ----- - -In the preceding example, we used MX4J 3.0.0. See the official MX4J -documentation for more information. - - - -[[jmx-proxy]] -=== Accessing MBeans through Proxies - -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"] ----- - - - - ----- - -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 through an -`MBeanServerConnection`. By default, the local `MBeanServer` is located and used, but -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"] ----- - - - - - - - - - ----- - -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`. - - - -[[jmx-notifications]] -=== Notifications - -Spring's JMX offering includes comprehensive support for JMX notifications. - - -[[jmx-notifications-listeners]] -==== Registering Listeners for Notifications - -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 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"] ----- - package com.example; - - import javax.management.AttributeChangeNotification; - import javax.management.Notification; - import javax.management.NotificationFilter; - import javax.management.NotificationListener; - - public class ConsoleLoggingNotificationListener - implements NotificationListener, NotificationFilter { - - public void handleNotification(Notification notification, Object handback) { - System.out.println(notification); - System.out.println(handback); - } - - public boolean isNotificationEnabled(Notification notification) { - return AttributeChangeNotification.class.isAssignableFrom(notification.getClass()); - } - - } ----- - -The following example adds `ConsoleLoggingNotificationListener` (defined in the preceding -example) to `notificationListenerMappings`: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - - - - ----- - -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, -as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - - - - ----- - -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"] ----- - - - - - - - ----- - -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 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 -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, as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - bean:name=testBean1 - - - - - - - - - - - - - ----- - -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"] ----- - - - - - - - - - - - - - - - - - bean:name=testBean1 - bean:name=testBean2 - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -(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 only for registering to receive `Notifications` but also -for publishing `Notifications`. - -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 through an `MBeanExporter` instance can implement the related -`NotificationPublisherAware` interface to gain access to a `NotificationPublisher` -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 javadoc of the -{api-spring-framework}/jmx/export/notification/NotificationPublisher.html[`NotificationPublisher`] -interface, managed beans that publish events through the `NotificationPublisher` -mechanism are not responsible for the state management of 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. You create a JMX -`Notification` instance (or an instance of an appropriate `Notification` 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`. - -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"] ----- - package org.springframework.jmx; - - import org.springframework.jmx.export.notification.NotificationPublisherAware; - import org.springframework.jmx.export.notification.NotificationPublisher; - import javax.management.Notification; - - public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware { - - private String name; - private int age; - private boolean isSuperman; - private NotificationPublisher publisher; - - // other getters and setters omitted for clarity - - public int add(int x, int y) { - int answer = x + y; - this.publisher.sendNotification(new Notification("add", this, 0)); - return answer; - } - - public void dontExposeMe() { - throw new RuntimeException(); - } - - public void setNotificationPublisher(NotificationPublisher notificationPublisher) { - this.publisher = notificationPublisher; - } - - } ----- - -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 -you can accept the coupling to both Spring and JMX, then do so. - - - -[[jmx-resources]] -=== Further Resources - -This section contains links to further resources about JMX: - -* The https://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX -homepage] at Oracle. -* The https://jcp.org/aboutJava/communityprocess/final/jsr003/index3.html[JMX - specification] (JSR-000003). -* The https://jcp.org/aboutJava/communityprocess/final/jsr160/index.html[JMX Remote API - specification] (JSR-000160). -* The http://mx4j.sourceforge.net/[MX4J homepage]. (MX4J is an open-source implementation of - various JMX specs.) - - - - -[[mail]] -== Email - -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 https://eclipse-ee4j.github.io/mail/[JavaMail / Jakarta Mail 1.6] library - -This library is freely available on the web -- for example, in Maven Central as -`com.sun.mail:jakarta.mail`. Please make sure to use the latest 1.6.x version -rather than Jakarta Mail 2.0 (which comes with a different package namespace). -**** - -The Spring Framework provides a helpful utility library for sending email that shields -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 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 called -`org.springframework.mail.javamail.MimeMessagePreparator` for preparing a `MimeMessage`. - - - -[[mail-usage]] -=== Usage - -Assume that we have a business interface called `OrderManager`, as the following example shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface OrderManager { - - void placeOrder(Order order); - - } ----- - -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. - - -[[mail-usage-simple]] -==== 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"] ----- - import org.springframework.mail.MailException; - import org.springframework.mail.MailSender; - import org.springframework.mail.SimpleMailMessage; - - public class SimpleOrderManager implements OrderManager { - - private MailSender mailSender; - private SimpleMailMessage templateMessage; - - public void setMailSender(MailSender mailSender) { - this.mailSender = mailSender; - } - - public void setTemplateMessage(SimpleMailMessage templateMessage) { - this.templateMessage = templateMessage; - } - - public void placeOrder(Order order) { - - // Do the business calculations... - - // Call the collaborators to persist the order... - - // Create a thread safe "copy" of the template message and customize it - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(order.getCustomer().getEmailAddress()); - msg.setText( - "Dear " + order.getCustomer().getFirstName() - + order.getCustomer().getLastName() - + ", thank you for placing order. Your order number is " - + order.getOrderNumber()); - try { - this.mailSender.send(msg); - } - catch (MailException ex) { - // simply log it and go on... - System.err.println(ex.getMessage()); - } - } - - } ----- - -The following example shows the bean definitions for the preceding code: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - ----- - - -[[mail-usage-mime]] -==== Using `JavaMailSender` and `MimeMessagePreparator` - -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"] ----- - import jakarta.mail.Message; - import jakarta.mail.MessagingException; - import jakarta.mail.internet.InternetAddress; - import jakarta.mail.internet.MimeMessage; - - import jakarta.mail.internet.MimeMessage; - import org.springframework.mail.MailException; - import org.springframework.mail.javamail.JavaMailSender; - import org.springframework.mail.javamail.MimeMessagePreparator; - - public class SimpleOrderManager implements OrderManager { - - private JavaMailSender mailSender; - - public void setMailSender(JavaMailSender mailSender) { - this.mailSender = mailSender; - } - - public void placeOrder(final Order order) { - // Do the business calculations... - // Call the collaborators to persist the order... - - MimeMessagePreparator preparator = new MimeMessagePreparator() { - public void prepare(MimeMessage mimeMessage) throws Exception { - mimeMessage.setRecipient(Message.RecipientType.TO, - new InternetAddress(order.getCustomer().getEmailAddress())); - mimeMessage.setFrom(new InternetAddress("mail@mycompany.example")); - mimeMessage.setText("Dear " + order.getCustomer().getFirstName() + " " + - order.getCustomer().getLastName() + ", thanks for your order. " + - "Your order number is " + order.getOrderNumber() + "."); - } - }; - - try { - this.mailSender.send(preparator); - } - catch (MailException ex) { - // simply log it and go on... - System.err.println(ex.getMessage()); - } - } - - } ----- - -NOTE: The mail code is a crosscutting concern and could well be a candidate for -refactoring into a <>, which could then -be run at appropriate joinpoints on the `OrderManager` target. - -The Spring Framework's mail support ships with the standard JavaMail implementation. -See the relevant javadoc for more information. - - - -[[mail-javamail-mime]] -=== Using the JavaMail `MimeMessageHelper` - -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"] ----- - // of course you would use DI in any real-world cases - JavaMailSenderImpl sender = new JavaMailSenderImpl(); - sender.setHost("mail.host.com"); - - MimeMessage message = sender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message); - helper.setTo("test@host.com"); - helper.setText("Thank you for ordering!"); - - sender.send(message); ----- - - -[[mail-javamail-mime-attachments]] -==== Sending Attachments and Inline Resources - -Multipart email messages allow for both attachments and inline resources. Examples of -inline resources include 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 -with a single JPEG image attachment: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - JavaMailSenderImpl sender = new JavaMailSenderImpl(); - sender.setHost("mail.host.com"); - - MimeMessage message = sender.createMimeMessage(); - - // use the true flag to indicate you need a multipart message - MimeMessageHelper helper = new MimeMessageHelper(message, true); - helper.setTo("test@host.com"); - - helper.setText("Check out this image!"); - - // let's attach the infamous windows Sample file (this time copied to c:/) - FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg")); - helper.addAttachment("CoolImage.jpg", file); - - sender.send(message); ----- - -[[mail-javamail-mime-attachments-inline]] -===== Inline Resources - -The following example shows you how to use the `MimeMessageHelper` to send an email -with an inline image: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - JavaMailSenderImpl sender = new JavaMailSenderImpl(); - sender.setHost("mail.host.com"); - - MimeMessage message = sender.createMimeMessage(); - - // use the true flag to indicate you need a multipart message - MimeMessageHelper helper = new MimeMessageHelper(message, true); - helper.setTo("test@host.com"); - - // use the true flag to indicate the text included is HTML - helper.setText("", true); - - // let's include the infamous windows Sample file (this time copied to c:/) - FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg")); - helper.addInline("identifier1234", res); - - sender.send(message); ----- - -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 by Using a Templating Library - -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, developers often do not create the content -of email messages 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. -* Changing the display structure of the email content requires writing Java code, - 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 -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 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 - -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 -implementations behind the common interfaces abstracts away the differences between Java -SE 5, Java SE 6, and Jakarta EE environments. - -Spring also features integration classes to support scheduling with the `Timer` -(part of the JDK since 1.3) and the Quartz Scheduler ( https://www.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 lets you invoke a method of -an existing target object (analogous to the normal `MethodInvokingFactoryBean` -operation). - - - -[[scheduling-task-executor]] -=== The Spring `TaskExecutor` Abstraction - -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 the Java SE and Jakarta 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 -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, you can also use this abstraction for your own needs. - - -[[scheduling-task-executor-types]] -==== `TaskExecutor` Types - -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`: - This implementation does not run 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 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`, 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` - configuration parameters as bean properties. There is rarely a need to use - `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`, we - recommend that you use a `ConcurrentTaskExecutor` instead. -* `DefaultManagedTaskExecutor`: - This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236 - compatible runtime environment (such as a Jakarta EE application server), - replacing a CommonJ WorkManager for that purpose. - - -[[scheduling-task-executor-usage]] -==== Using a `TaskExecutor` - -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"] ----- - import org.springframework.core.task.TaskExecutor; - - public class TaskExecutorExample { - - private class MessagePrinterTask implements Runnable { - - private String message; - - public MessagePrinterTask(String message) { - this.message = message; - } - - public void run() { - System.out.println(message); - } - } - - private TaskExecutor taskExecutor; - - public TaskExecutorExample(TaskExecutor taskExecutor) { - this.taskExecutor = taskExecutor; - } - - public void printMessages() { - for(int i = 0; i < 25; i++) { - taskExecutor.execute(new MessagePrinterTask("Message" + i)); - } - } - } ----- - -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 run. - -To configure the rules that the `TaskExecutor` uses, we expose simple bean properties: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - ----- - - - -[[scheduling-task-scheduler]] -=== The Spring `TaskScheduler` Abstraction - -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"] ----- - public interface TaskScheduler { - - ScheduledFuture schedule(Runnable task, Trigger trigger); - - ScheduledFuture schedule(Runnable task, Instant startTime); - - ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period); - - ScheduledFuture scheduleAtFixedRate(Runnable task, Duration period); - - ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay); - - ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay); - ----- - -The simplest method is the one named `schedule` that takes only a `Runnable` and an `Instant`. -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 -much more flexible. - - -[[scheduling-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, as the following listing shows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface Trigger { - - Date nextExecutionTime(TriggerContext triggerContext); - } ----- - -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). The following listing shows the available methods for `Trigger` implementations. - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public interface TriggerContext { - - Date lastScheduledExecutionTime(); - - Date lastActualExecutionTime(); - - Date lastCompletionTime(); - } ----- - - -[[scheduling-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 -<>. -For 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 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 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 you can configure such `Triggers` -externally and, therefore, easily modify or extend them. - - -[[scheduling-task-scheduler-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` -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 Jakarta EE 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 -through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a -`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. - - - -[[scheduling-annotation-support]] -=== Annotation Support for Scheduling and Asynchronous Execution - -Spring provides annotation support for both task scheduling and asynchronous method -execution. - - -[[scheduling-enable-annotation-support]] -==== Enable Scheduling Annotations - -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"] ----- - @Configuration - @EnableAsync - @EnableScheduling - public class AppConfig { - } ----- - -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, you can use the `` element, -as the following example shows: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - ----- - -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 -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. - - -[[scheduling-annotation-support-scheduled]] -==== The `@Scheduled` annotation - -You can add the `@Scheduled` annotation to a method, along with trigger metadata. For -example, the following method is invoked every five seconds (5000 milliseconds) 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"] ----- - @Scheduled(fixedDelay = 5000) - public void doSomething() { - // something that should run periodically - } ----- - -[NOTE] -==== -By default, milliseconds will be used as the time unit for fixed delay, fixed rate, and -initial delay values. If you would like to use a different time unit such as seconds or -minutes, you can configure this via the `timeUnit` attribute in `@Scheduled`. - -For example, the previous example can also be written as follows. - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS) - public void doSomething() { - // something that should run periodically - } ----- -==== - -If you need a fixed-rate execution, you can use the `fixedRate` attribute 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"] ----- - @Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS) - public void doSomething() { - // something that should run periodically - } ----- - -For fixed-delay and fixed-rate tasks, you can specify an initial delay by indicating the -amount of time to wait before the first execution of the method, as the following -`fixedRate` example shows. - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Scheduled(initialDelay = 1000, fixedRate = 5000) - public void doSomething() { - // something that should run periodically - } ----- - -If simple periodic scheduling is not expressive enough, you can provide a -<>. -The following example runs only on weekdays: - -[source,java,indent=0] -[subs="verbatim"] ----- - @Scheduled(cron="*/5 * * * * MON-FRI") - public void doSomething() { - // something that should run on weekdays only - } ----- - -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 accept any -arguments. If the method needs to interact with other objects from the application -context, those would typically have been provided through dependency injection. - -[NOTE] -==== -As of Spring Framework 4.3, `@Scheduled` methods are supported on beans of any scope. - -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 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 - -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"] ----- - @Async - void doSomething() { - // this will be run asynchronously - } ----- - -Unlike the methods annotated with the `@Scheduled` annotation, these methods can expect -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"] ----- - @Async - void doSomething(String s) { - // this will be run 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 -asynchronous execution so that the caller can perform other tasks prior to calling -`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"] ----- - @Async - Future returnSomething(int i) { - // this will be run asynchronously - } ----- - -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 -asynchronous task and for immediate composition with further processing steps. - -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"] ----- - public class SampleBeanImpl implements SampleBean { - - @Async - void doSomething() { - // ... - } - - } - - public class SampleBeanInitializer { - - private final SampleBean bean; - - public SampleBeanInitializer(SampleBean bean) { - this.bean = bean; - } - - @PostConstruct - public void initialize() { - bean.doSomething(); - } - - } ----- - -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` - -By default, when specifying `@Async` on a method, the executor that is used is the -one <>, -i.e. the "`annotation-driven`" element if you are using XML or your `AsyncConfigurer` -implementation, if any. 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"] ----- - @Async("otherExecutor") - void doSomething(String s) { - // this will be run 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). - - -[[scheduling-annotation-support-exception]] -==== 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 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"] ----- - public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { - - @Override - public void handleUncaughtException(Throwable ex, Method method, Object... params) { - // handle exception - } - } ----- - -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 - -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 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 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 following creates a `ThreadPoolTaskExecutor` instance: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - ----- - -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 one thing, the thread pool for -a `ThreadPoolTaskExecutor` is itself more configurable. 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"] ----- - ----- - -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, see the documentation for -https://docs.oracle.com/javase/8/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, 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, -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, 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 -when using an unbounded queue). - -Consider the case, as mentioned above, when a task is rejected. By default, when a -task is rejected, 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, 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 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"] ----- - ----- - -Finally, the `keep-alive` setting determines the time limit (in seconds) for which threads -may remain idle before being stopped. 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 get stopped. A time value of zero causes excess threads to stop -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"] ----- - ----- - - -[[scheduling-task-namespace-scheduled-tasks]] -==== 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. The following listing shows a simple example: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - ----- - -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 run 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 -to provide a <>. -The following example shows these other options: - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - - - - ----- - - - -[[scheduling-cron-expression]] -=== Cron Expressions - -All Spring cron expressions have to conform to the same format, whether you are using them in -<>, -<>, -or someplace else. -A well-formed cron expression, such as `* * * * * *`, consists of six space-separated time and date -fields, each with its own range of valid values: - - -.... - ┌───────────── second (0-59) - │ ┌───────────── minute (0 - 59) - │ │ ┌───────────── hour (0 - 23) - │ │ │ ┌───────────── day of the month (1 - 31) - │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC) - │ │ │ │ │ ┌───────────── day of the week (0 - 7) - │ │ │ │ │ │ (0 or 7 is Sunday, or MON-SUN) - │ │ │ │ │ │ - * * * * * * -.... - -There are some rules that apply: - -* A field may be an asterisk (`*`), which always stands for "`first-last`". -For the day-of-the-month or day-of-the-week fields, a question mark (`?`) may be used instead of an -asterisk. -* Commas (`,`) are used to separate items of a list. -* Two numbers separated with a hyphen (`-`) express a range of numbers. -The specified range is inclusive. -* Following a range (or `*`) with `/` specifies the interval of the number's value through the range. -* English names can also be used for the month and day-of-week fields. -Use the first three letters of the particular day or month (case does not matter). -* The day-of-month and day-of-week fields can contain a `L` character, which has a different meaning -** In the day-of-month field, `L` stands for _the last day of the month_. -If followed by a negative offset (that is, `L-n`), it means _``n``th-to-last day of the month_. -** In the day-of-week field, `L` stands for _the last day of the week_. -If prefixed by a number or three-letter name (`dL` or `DDDL`), it means _the last day of week (`d` -or `DDD`) in the month_. -* The day-of-month field can be `nW`, which stands for _the nearest weekday to day of the month ``n``_. -If `n` falls on Saturday, this yields the Friday before it. -If `n` falls on Sunday, this yields the Monday after, which also happens if `n` is `1` and falls on -a Saturday (that is: `1W` stands for _the first weekday of the month_). -* If the day-of-month field is `LW`, it means _the last weekday of the month_. -* The day-of-week field can be `d#n` (or `DDD#n`), which stands for _the ``n``th day of week `d` -(or ``DDD``) in the month_. - -Here are some examples: - -|=== -| Cron Expression | Meaning - -|`0 0 * * * *` | top of every hour of every day -|`*/10 * * * * *` | every ten seconds -| `0 0 8-10 * * *` | 8, 9 and 10 o'clock of every day -| `0 0 6,19 * * *` | 6:00 AM and 7:00 PM every day -| `0 0/30 8-10 * * *` | 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day -| `0 0 9-17 * * MON-FRI`| on the hour nine-to-five weekdays -| `0 0 0 25 DEC ?` | every Christmas Day at midnight -| `0 0 0 L * *` | last day of the month at midnight -| `0 0 0 L-3 * *` | third-to-last day of the month at midnight -| `0 0 0 * * 5L` | last Friday of the month at midnight -| `0 0 0 * * THUL` | last Thursday of the month at midnight -| `0 0 0 1W * *` | first weekday of the month at midnight -| `0 0 0 LW * *` | last weekday of the month at midnight -| `0 0 0 ? * 5#2` | the second Friday in the month at midnight -| `0 0 0 ? * MON#1` | the first Monday in the month at midnight -|=== - -==== Macros - -Expressions such as `0 0 * * * *` are hard for humans to parse and are, therefore, hard to fix in case of bugs. -To improve readability, Spring supports the following macros, which represent commonly used sequences. -You can use these macros instead of the six-digit value, thus: `@Scheduled(cron = "@hourly")`. - -|=== -|Macro | Meaning - -| `@yearly` (or `@annually`) | once a year (`0 0 0 1 1 *`) -| `@monthly` | once a month (`0 0 0 1 * *`) -| `@weekly` | once a week (`0 0 0 * * 0`) -| `@daily` (or `@midnight`) | once a day (`0 0 0 * * *`), or -| `@hourly` | once an hour, (`0 0 * * * *`) -|=== - - - -[[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, see -https://www.quartz-scheduler.org/[]. For convenience purposes, Spring offers a couple of -classes that simplify using Quartz within Spring-based applications. - - -[[scheduling-quartz-jobdetail]] -==== Using the `JobDetailFactoryBean` - -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"] ----- - - - - - - - - ----- - -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 the following example, -the `ExampleJob` contains a bean property named `timeout`, and the `JobDetail` -has it applied automatically: - -[source,java,indent=0] -[subs="verbatim"] ----- - package example; - - public class ExampleJob extends QuartzJobBean { - - private int timeout; - - /** - * Setter called after the ExampleJob is instantiated - * with the value from the JobDetailFactoryBean (5) - */ - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException { - // do the actual work - } - } ----- - -All additional properties from the job data map are available to you as well. - -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` (`exampleJob` in the preceding example above). - - -[[scheduling-quartz-method-invoking-job]] -==== Using the `MethodInvokingJobDetailFactoryBean` - -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"] ----- - - - - ----- - -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"] ----- - public class ExampleBusinessObject { - - // properties and collaborators - - public void doIt() { - // do the actual work - } - } ----- - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - ----- - -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 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"] ----- - - - - - ----- - -NOTE: By default, jobs will run in a concurrent fashion. - - -[[scheduling-quartz-cron]] -==== Wiring up Jobs by Using Triggers and `SchedulerFactoryBean` - -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`. - -Triggers need to be scheduled. Spring offers a `SchedulerFactoryBean` that exposes -triggers to be set as properties. `SchedulerFactoryBean` schedules the actual jobs with -those triggers. - -The following listing uses both a `SimpleTriggerFactoryBean` and a `CronTriggerFactoryBean`: - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - - - - - - - - - - - ----- - -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"] ----- - - - - - - - - ----- - -More properties are available for the `SchedulerFactoryBean`, such as the calendars used by the -job details, properties to customize Quartz with, and a Spring-provided JDBC DataSource. See -the {api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`] -javadoc for more information. - -NOTE: `SchedulerFactoryBean` also recognizes a `quartz.properties` file in the classpath, -based on Quartz property keys, as with regular Quartz configuration. Please note that many -`SchedulerFactoryBean` settings interact with common Quartz settings in the properties file; -it is therefore not recommended to specify values at both levels. For example, do not set -an "org.quartz.jobStore.class" property if you mean to rely on a Spring-provided DataSource, -or specify an `org.springframework.scheduling.quartz.LocalDataSourceJobStore` variant which -is a full-fledged replacement for the standard `org.quartz.impl.jdbcjobstore.JobStoreTX`. - - - - -[[cache]] -== Cache Abstraction - -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. - -In Spring Framework 4.1, the cache abstraction was significantly extended with support -for <> and more customization options. - - - -[[cache-strategies]] -=== Understanding the Cache Abstraction - -.Cache vs Buffer -**** - -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 have to wait -for the other (which affects performance), the buffer alleviates this by allowing entire -blocks of data to move at once rather than in small chunks. The data is written and read -only once from the buffer. Furthermore, the buffers are visible to at least one party -that is aware of it. - -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. - -You can find a further explanation of the differences between a buffer and a cache -https://en.wikipedia.org/wiki/Cache_(computing)#The_difference_between_buffer_and_cache[here]. -**** - -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 applies a caching behavior that checks -whether the method has been already invoked for the given arguments. If it has been -invoked, the cached result is returned without having to invoke the actual method. -If the method has not been invoked, then it is invoked, 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 invoked only -once for a given set of parameters and the result reused without having to actually -invoke the method again. The caching logic is applied transparently without any -interference to the invoker. - -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 they are invoked. - -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. - -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. - -Spring provides <> of that abstraction: -JDK `java.util.concurrent.ConcurrentMap` based caches, Gemfire cache, -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 for multi-threaded and -multi-process environments, as such features are handled by the cache implementation. - -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. See the documentation of your cache provider for more details. - -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 policies. -* Cache configuration: The backing cache where the data is stored and from which it is read. - - - -[[cache-annotations]] -=== Declarative Annotation-based Caching - -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. - - -[[cache-annotations-cacheable]] -==== The `@Cacheable` Annotation - -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 invoke the method. In its simplest form, the annotation declaration -requires the name 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 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 -already been run 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 invoking 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 are also updated, even though -the cached method was not actually invoked. - -The following example uses `@Cacheable` on the `findBook` method with multiple caches: - -[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. 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 than 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, -you need to change the strategy. - -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, -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. - -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. -==== - -[[cache-annotations-cacheable-key]] -===== Custom Key Generation Declaration - -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). 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. Furthermore, what if only one of the two is important -while the other is not? - -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 works for all methods. - -The following examples use various SpEL declarations (if you are not familiar with SpEL, -do yourself a favor and read <>): - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Cacheable(cacheNames="books", key="#isbn") - public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) - - @Cacheable(cacheNames="books", key="#isbn.rawNumber") - public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) - - @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)") - public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) ----- - -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 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 -that specifies both results in an exception. - -[[cache-annotations-cacheable-default-cache-resolver]] -===== Default Cache Resolution - -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, you need to implement the -`org.springframework.cache.interceptor.CacheResolver` interface. - -[[cache-annotations-cacheable-cache-resolver]] -===== Custom Cache Resolution - -The default cache resolution fits well for applications that work with a -single `CacheManager` and have no complex cache resolution requirements. - -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") <1> - public Book findBook(ISBN isbn) {...} ----- -<1> Specifying `anotherCacheManager`. - - -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") <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` -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 -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 - -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 -of caching. - -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) <1> - public Foo executeExpensiveOperation(String id) {...} ----- -<1> Using the `sync` attribute. - -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 - -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 use cases 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 invoked 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") <1> - public Book findBook(String name) ----- -<1> Setting a condition on `@Cacheable`. - - -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 invoked. 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") <1> - public Book findBook(String name) ----- -<1> Using the `unless` attribute to block hardbacks. - - -The cache abstraction supports `java.util.Optional` return types. If an `Optional` value -is _present_, it will be stored in the associated cache. If an `Optional` value is not -present, `null` will be stored in the associated cache. `#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`. Since it might be -`null`, we use SpEL's <>. - -[[cache-spel-context]] -===== Available Caching SpEL Evaluation Context - -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]] -.Cache SpEL available metadata -|=== -| Name| Location| Description| Example - -| `methodName` -| Root object -| The name of the method being invoked -| `#root.methodName` - -| `method` -| Root object -| The method being invoked -| `#root.method.name` - -| `target` -| Root object -| The target object being invoked -| `#root.target` - -| `targetClass` -| Root object -| The class of the target being invoked -| `#root.targetClass` - -| `args` -| Root object -| The arguments (as array) used for invoking the target -| `#root.args[0]` - -| `caches` -| Root object -| Collection of caches against which the current method is run -| `#root.caches[0].name` - -| Argument name -| Evaluation context -| Name of any of the method arguments. If the names are not available - (perhaps 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 -| 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. -| `#result` -|=== - - -[[cache-annotations-put]] -==== The `@CachePut` Annotation - -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 invoked 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. The following example uses the `@CachePut` annotation: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @CachePut(cacheNames="book", key="#isbn") - public Book updateBook(ISBN isbn, BookDescriptor descriptor) ----- - -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 invocation to be skipped by using the cache, the former forces the invocation in -order to run 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 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]] -==== 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. 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, and features an extra parameter -(`allEntries`) that indicates whether a cache-wide eviction needs to be performed -rather than 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) <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 than 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). - -You can also indicate whether the eviction should occur after (the default) or before -the method is invoked 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 run. If the method does not -run (as it might be cached) or an exception is thrown, the eviction does not occur. -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. - -Note that `void` methods can be used with `@CacheEvict` - as the methods act as a -trigger, the return values are ignored (as they do not interact with the cache). This is -not the case with `@Cacheable` which adds data to the cache or updates data in the cache -and, thus, requires a result. - - -[[cache-annotations-caching]] -==== The `@Caching` Annotation - -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]] -==== The `@CacheConfig` annotation - -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 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") <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 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 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. - - -[[cache-annotation-enable]] -==== 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 -declaratively enabled (which means if you ever suspect caching is to blame, you can -disable it by removing only one configuration line rather than all the annotations in -your code). - -To enable caching annotations add the annotation `@EnableCaching` to one of your -`@Configuration` classes: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Configuration - @EnableCaching - public class AppConfig { - } ----- - -Alternatively, for XML configuration you can use the `cache:annotation-driven` element: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - ----- - -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 -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. - -NOTE: For more detail about advanced customizations (using Java configuration) that are -required to implement `CachingConfigurer`, see the -{api-spring-framework}/cache/annotation/CachingConfigurer.html[javadoc]. - -[[cache-annotation-driven-settings]] -.Cache annotation settings -[cols="1,1,1,3"] -|=== -| XML Attribute | Annotation Attribute | Default | Description - -| `cache-manager` -| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`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 the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`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 needs to be specified only as an alternative to - the 'cache-manager' attribute. - -| `key-generator` -| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`CachingConfigurer`] javadoc) -| `SimpleKeyGenerator` -| Name of the custom key generator to use. - -| `error-handler` -| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`CachingConfigurer`] javadoc) -| `SimpleCacheErrorHandler` -| 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 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` - 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` -| 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`, 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` -| `order` -| 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 AOP advice, see <>.) - No specified ordering means that the AOP subsystem determines the order of the advice. -|=== - -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 checks for beans only in your controllers, not your services. -See <> for more information. - -.Method visibility and cache annotations -**** -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 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 -classes) with the `@Cache{asterisk}` annotations, as opposed to annotating interfaces. -You certainly can place an `@Cache{asterisk}` annotation on an interface (or an interface -method), but this works only if you use the proxy mode (`mode="proxy"`). If you use the -weaving-based aspect (`mode="aspectj"`), the caching settings are not recognized on -interface-level declarations by the weaving infrastructure. - -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`). - - -[[cache-annotation-stereotype]] -==== Using Custom Annotations - -.Custom annotation and 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 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"] ----- - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @Cacheable(cacheNames="books", key="#isbn") - public @interface SlowService { - } ----- - -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) ----- - -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 -<>, annotation-driven behavior needs to be enabled. - - - -[[cache-jsr-107]] -=== JCache (JSR-107) Annotations - -Since version 4.1, Spring's caching abstraction fully supports the JCache standard -(JSR-107) annotations: `@CacheResult`, `@CachePut`, `@CacheRemove`, and `@CacheRemoveAll` -as well as the `@CacheDefaults`, `@CacheKey`, and `@CacheValue` companions. -You can use these annotations even 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 - -For those who are familiar with Spring's caching annotations, the following table -describes the main differences between the Spring annotations and their JSR-107 -counterparts: - -.Spring vs. JSR-107 caching annotations -[cols="1,1,3"] -|=== -| Spring | JSR-107 | Remark - -| `@Cacheable` -| `@CacheResult` -| Fairly similar. `@CacheResult` can cache specific exceptions and force the - execution of the method regardless of the content of the cache. - -| `@CachePut` -| `@CachePut` -| While Spring updates the cache with the result of the method invocation, JCache - 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 conditional eviction when the - method invocation results in an exception. - -| `@CacheEvict(allEntries=true)` -| `@CacheRemoveAll` -| See `@CacheRemove`. - -| `@CacheConfig` -| `@CacheDefaults` -| Lets you configure the same concepts, in a similar fashion. -|=== - -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. See the javadoc -of `@CacheResult#cacheName()` for more information. - -`CacheResolver` instances are retrieved by a `CacheResolverFactory`. It is 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) <1> - public Book findBook(ISBN isbn) ----- -<1> Customizing the factory for this operation. - -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. - -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 -similar to Spring's <>. For instance, the following are identical operations, one using -Spring's abstraction and the other using JCache: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Cacheable(cacheNames="books", key="#isbn") - public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) - - @CacheResult(cacheName="books") - public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse, boolean includeUsed) ----- - -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. 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"] ----- - @CacheResult(cacheName="books", exceptionCacheName="failures" - cachedExceptions = InvalidIsbnNotFoundException.class) - public Book findBook(ISBN isbn) ----- - - -==== Enabling JSR-107 Support - -You do not need to do anything specific to enable the JSR-107 support alongside Spring's -declarative annotation support. Both `@EnableCaching` and the `cache:annotation-driven` -XML 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 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 - -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 example -from the previous section can be translated into the following example: - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - - - - - - - - - - - - - - ----- - -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 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 - -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). - - -[[cache-store-configuration-jdk]] -==== JDK `ConcurrentMap`-based Cache - -The JDK-based `Cache` implementation resides under -`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"] ----- - - - - - - - - - ----- - -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, persistence capabilities, -or eviction contracts. - - -[[cache-store-configuration-eviction]] -==== Ehcache-based Cache - -Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it. See -<> for details. - - -[[cache-store-configuration-caffeine]] -==== Caffeine Cache - -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. - -The following example configures a `CacheManager` that creates the cache on demand: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - ----- - -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"] ----- - - - - default - books - - - ----- - -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, -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), see the -{docs-spring-gemfire}/html/[Spring Data GemFire reference documentation]. - - -[[cache-store-configuration-jsr107]] -==== JSR-107 Cache - -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, you need to declare the appropriate `CacheManager`. -The following example shows how to do so: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - ----- - - -[[cache-store-configuration-noop]] -==== Dealing with Caches without a Backing Store - -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 than removing the -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 invoked every time. -The following example shows how to do so: - -[source,xml,indent=0,subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -The `CompositeCacheManager` in the preceding chains multiple `CacheManager` instances 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 earlier in the example) is handled by -the no-op cache, which does not store any information, causing the target method to be -invoked every time. - - - -[[cache-plug]] -=== Plugging-in Different Back-end Caches - -Clearly, there are plenty of caching products out there that you can use as a backing -store. For those that do not support JSR-107 you need to provide a `CacheManager` and a -`Cache` implementation. This may sound harder than it is, since, in practice, the classes -tend to be simple https://en.wikipedia.org/wiki/Adapter_pattern[adapters] that map the -caching abstraction framework on top of the storage API, as the _Caffeine_ 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). - - - -[[cache-specific-config]] -=== 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. +include::integration/jmx.adoc[leveloffset=+1] +include::integration/email.adoc[leveloffset=+1] +include::integration/scheduling.adoc[leveloffset=+1] +include::integration/cache.adoc[leveloffset=+1] include::integration/integration-appendix.adoc[leveloffset=+1] diff --git a/framework-docs/src/docs/asciidoc/integration/cache.adoc b/framework-docs/src/docs/asciidoc/integration/cache.adoc new file mode 100644 index 0000000000..765a1c65ad --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/cache.adoc @@ -0,0 +1,1070 @@ +[[cache]] += Cache Abstraction + +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. + +In Spring Framework 4.1, the cache abstraction was significantly extended with support +for <> and more customization options. + + + +[[cache-strategies]] +== Understanding the Cache Abstraction + +.Cache vs Buffer +**** + +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 have to wait +for the other (which affects performance), the buffer alleviates this by allowing entire +blocks of data to move at once rather than in small chunks. The data is written and read +only once from the buffer. Furthermore, the buffers are visible to at least one party +that is aware of it. + +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. + +You can find a further explanation of the differences between a buffer and a cache +https://en.wikipedia.org/wiki/Cache_(computing)#The_difference_between_buffer_and_cache[here]. +**** + +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 applies a caching behavior that checks +whether the method has been already invoked for the given arguments. If it has been +invoked, the cached result is returned without having to invoke the actual method. +If the method has not been invoked, then it is invoked, 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 invoked only +once for a given set of parameters and the result reused without having to actually +invoke the method again. The caching logic is applied transparently without any +interference to the invoker. + +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 they are invoked. + +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. + +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. + +Spring provides <> of that abstraction: +JDK `java.util.concurrent.ConcurrentMap` based caches, Gemfire cache, +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 for multi-threaded and +multi-process environments, as such features are handled by the cache implementation. + +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. See the documentation of your cache provider for more details. + +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 policies. +* Cache configuration: The backing cache where the data is stored and from which it is read. + + + +[[cache-annotations]] +== Declarative Annotation-based Caching + +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. + + +[[cache-annotations-cacheable]] +=== The `@Cacheable` Annotation + +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 invoke the method. In its simplest form, the annotation declaration +requires the name 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 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 +already been run 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 invoking 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 are also updated, even though +the cached method was not actually invoked. + +The following example uses `@Cacheable` on the `findBook` method with multiple caches: + +[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. 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 than 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, +you need to change the strategy. + +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, +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. + +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. +==== + +[[cache-annotations-cacheable-key]] +==== Custom Key Generation Declaration + +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). 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. Furthermore, what if only one of the two is important +while the other is not? + +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 works for all methods. + +The following examples use various SpEL declarations (if you are not familiar with SpEL, +do yourself a favor and read <>): + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Cacheable(cacheNames="books", key="#isbn") + public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) + + @Cacheable(cacheNames="books", key="#isbn.rawNumber") + public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) + + @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)") + public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) +---- + +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 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 +that specifies both results in an exception. + +[[cache-annotations-cacheable-default-cache-resolver]] +==== Default Cache Resolution + +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, you need to implement the +`org.springframework.cache.interceptor.CacheResolver` interface. + +[[cache-annotations-cacheable-cache-resolver]] +==== Custom Cache Resolution + +The default cache resolution fits well for applications that work with a +single `CacheManager` and have no complex cache resolution requirements. + +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") <1> + public Book findBook(ISBN isbn) {...} +---- +<1> Specifying `anotherCacheManager`. + + +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") <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` +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 +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 + +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 +of caching. + +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) <1> + public Foo executeExpensiveOperation(String id) {...} +---- +<1> Using the `sync` attribute. + +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 + +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 use cases 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 invoked 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") <1> + public Book findBook(String name) +---- +<1> Setting a condition on `@Cacheable`. + + +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 invoked. 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") <1> + public Book findBook(String name) +---- +<1> Using the `unless` attribute to block hardbacks. + + +The cache abstraction supports `java.util.Optional` return types. If an `Optional` value +is _present_, it will be stored in the associated cache. If an `Optional` value is not +present, `null` will be stored in the associated cache. `#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`. Since it might be +`null`, we use SpEL's <>. + +[[cache-spel-context]] +==== Available Caching SpEL Evaluation Context + +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]] +.Cache SpEL available metadata +|=== +| Name| Location| Description| Example + +| `methodName` +| Root object +| The name of the method being invoked +| `#root.methodName` + +| `method` +| Root object +| The method being invoked +| `#root.method.name` + +| `target` +| Root object +| The target object being invoked +| `#root.target` + +| `targetClass` +| Root object +| The class of the target being invoked +| `#root.targetClass` + +| `args` +| Root object +| The arguments (as array) used for invoking the target +| `#root.args[0]` + +| `caches` +| Root object +| Collection of caches against which the current method is run +| `#root.caches[0].name` + +| Argument name +| Evaluation context +| Name of any of the method arguments. If the names are not available + (perhaps 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 +| 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. +| `#result` +|=== + + +[[cache-annotations-put]] +=== The `@CachePut` Annotation + +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 invoked 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. The following example uses the `@CachePut` annotation: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @CachePut(cacheNames="book", key="#isbn") + public Book updateBook(ISBN isbn, BookDescriptor descriptor) +---- + +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 invocation to be skipped by using the cache, the former forces the invocation in +order to run 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 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]] +=== 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. 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, and features an extra parameter +(`allEntries`) that indicates whether a cache-wide eviction needs to be performed +rather than 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) <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 than 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). + +You can also indicate whether the eviction should occur after (the default) or before +the method is invoked 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 run. If the method does not +run (as it might be cached) or an exception is thrown, the eviction does not occur. +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. + +Note that `void` methods can be used with `@CacheEvict` - as the methods act as a +trigger, the return values are ignored (as they do not interact with the cache). This is +not the case with `@Cacheable` which adds data to the cache or updates data in the cache +and, thus, requires a result. + + +[[cache-annotations-caching]] +=== The `@Caching` Annotation + +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]] +=== The `@CacheConfig` annotation + +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 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") <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 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 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. + + +[[cache-annotation-enable]] +=== 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 +declaratively enabled (which means if you ever suspect caching is to blame, you can +disable it by removing only one configuration line rather than all the annotations in +your code). + +To enable caching annotations add the annotation `@EnableCaching` to one of your +`@Configuration` classes: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Configuration + @EnableCaching + public class AppConfig { + } +---- + +Alternatively, for XML configuration you can use the `cache:annotation-driven` element: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + +---- + +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 +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. + +NOTE: For more detail about advanced customizations (using Java configuration) that are +required to implement `CachingConfigurer`, see the +{api-spring-framework}/cache/annotation/CachingConfigurer.html[javadoc]. + +[[cache-annotation-driven-settings]] +.Cache annotation settings +[cols="1,1,1,3"] +|=== +| XML Attribute | Annotation Attribute | Default | Description + +| `cache-manager` +| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`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 the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`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 needs to be specified only as an alternative to + the 'cache-manager' attribute. + +| `key-generator` +| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`CachingConfigurer`] javadoc) +| `SimpleKeyGenerator` +| Name of the custom key generator to use. + +| `error-handler` +| N/A (see the {api-spring-framework}/cache/annotation/CachingConfigurer.html[`CachingConfigurer`] javadoc) +| `SimpleCacheErrorHandler` +| 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 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` + 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` +| 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`, 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` +| `order` +| 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 AOP advice, see <>.) + No specified ordering means that the AOP subsystem determines the order of the advice. +|=== + +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 checks for beans only in your controllers, not your services. +See <> for more information. + +.Method visibility and cache annotations +**** +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 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 +classes) with the `@Cache{asterisk}` annotations, as opposed to annotating interfaces. +You certainly can place an `@Cache{asterisk}` annotation on an interface (or an interface +method), but this works only if you use the proxy mode (`mode="proxy"`). If you use the +weaving-based aspect (`mode="aspectj"`), the caching settings are not recognized on +interface-level declarations by the weaving infrastructure. + +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`). + + +[[cache-annotation-stereotype]] +=== Using Custom Annotations + +.Custom annotation and 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 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"] +---- + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + @Cacheable(cacheNames="books", key="#isbn") + public @interface SlowService { + } +---- + +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) +---- + +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 +<>, annotation-driven behavior needs to be enabled. + + + +[[cache-jsr-107]] +== JCache (JSR-107) Annotations + +Since version 4.1, Spring's caching abstraction fully supports the JCache standard +(JSR-107) annotations: `@CacheResult`, `@CachePut`, `@CacheRemove`, and `@CacheRemoveAll` +as well as the `@CacheDefaults`, `@CacheKey`, and `@CacheValue` companions. +You can use these annotations even 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 + +For those who are familiar with Spring's caching annotations, the following table +describes the main differences between the Spring annotations and their JSR-107 +counterparts: + +.Spring vs. JSR-107 caching annotations +[cols="1,1,3"] +|=== +| Spring | JSR-107 | Remark + +| `@Cacheable` +| `@CacheResult` +| Fairly similar. `@CacheResult` can cache specific exceptions and force the + execution of the method regardless of the content of the cache. + +| `@CachePut` +| `@CachePut` +| While Spring updates the cache with the result of the method invocation, JCache + 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 conditional eviction when the + method invocation results in an exception. + +| `@CacheEvict(allEntries=true)` +| `@CacheRemoveAll` +| See `@CacheRemove`. + +| `@CacheConfig` +| `@CacheDefaults` +| Lets you configure the same concepts, in a similar fashion. +|=== + +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. See the javadoc +of `@CacheResult#cacheName()` for more information. + +`CacheResolver` instances are retrieved by a `CacheResolverFactory`. It is 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) <1> + public Book findBook(ISBN isbn) +---- +<1> Customizing the factory for this operation. + +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. + +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 +similar to Spring's <>. For instance, the following are identical operations, one using +Spring's abstraction and the other using JCache: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Cacheable(cacheNames="books", key="#isbn") + public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) + + @CacheResult(cacheName="books") + public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse, boolean includeUsed) +---- + +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. 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"] +---- + @CacheResult(cacheName="books", exceptionCacheName="failures" + cachedExceptions = InvalidIsbnNotFoundException.class) + public Book findBook(ISBN isbn) +---- + + +=== Enabling JSR-107 Support + +You do not need to do anything specific to enable the JSR-107 support alongside Spring's +declarative annotation support. Both `@EnableCaching` and the `cache:annotation-driven` +XML 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 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 + +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 example +from the previous section can be translated into the following example: + +[source,xml,indent=0] +[subs="verbatim"] +---- + + + + + + + + + + + + + + + + + +---- + +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 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 + +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). + + +[[cache-store-configuration-jdk]] +=== JDK `ConcurrentMap`-based Cache + +The JDK-based `Cache` implementation resides under +`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"] +---- + + + + + + + + + +---- + +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, persistence capabilities, +or eviction contracts. + + +[[cache-store-configuration-eviction]] +=== Ehcache-based Cache + +Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it. See +<> for details. + + +[[cache-store-configuration-caffeine]] +=== Caffeine Cache + +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. + +The following example configures a `CacheManager` that creates the cache on demand: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + +---- + +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"] +---- + + + + default + books + + + +---- + +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, +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), see the +{docs-spring-gemfire}/html/[Spring Data GemFire reference documentation]. + + +[[cache-store-configuration-jsr107]] +=== JSR-107 Cache + +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, you need to declare the appropriate `CacheManager`. +The following example shows how to do so: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + +---- + + +[[cache-store-configuration-noop]] +=== Dealing with Caches without a Backing Store + +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 than removing the +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 invoked every time. +The following example shows how to do so: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +The `CompositeCacheManager` in the preceding chains multiple `CacheManager` instances 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 earlier in the example) is handled by +the no-op cache, which does not store any information, causing the target method to be +invoked every time. + + + +[[cache-plug]] +== Plugging-in Different Back-end Caches + +Clearly, there are plenty of caching products out there that you can use as a backing +store. For those that do not support JSR-107 you need to provide a `CacheManager` and a +`Cache` implementation. This may sound harder than it is, since, in practice, the classes +tend to be simple https://en.wikipedia.org/wiki/Adapter_pattern[adapters] that map the +caching abstraction framework on top of the storage API, as the _Caffeine_ 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). + + + +[[cache-specific-config]] +== 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/framework-docs/src/docs/asciidoc/integration/email.adoc b/framework-docs/src/docs/asciidoc/integration/email.adoc new file mode 100644 index 0000000000..f0c6581e8d --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/email.adoc @@ -0,0 +1,302 @@ +[[mail]] += Email + +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 https://eclipse-ee4j.github.io/mail/[JavaMail / Jakarta Mail 1.6] library + +This library is freely available on the web -- for example, in Maven Central as +`com.sun.mail:jakarta.mail`. Please make sure to use the latest 1.6.x version +rather than Jakarta Mail 2.0 (which comes with a different package namespace). +**** + +The Spring Framework provides a helpful utility library for sending email that shields +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 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 called +`org.springframework.mail.javamail.MimeMessagePreparator` for preparing a `MimeMessage`. + + + +[[mail-usage]] +== Usage + +Assume that we have a business interface called `OrderManager`, as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface OrderManager { + + void placeOrder(Order order); + + } +---- + +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. + + +[[mail-usage-simple]] +=== 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"] +---- + import org.springframework.mail.MailException; + import org.springframework.mail.MailSender; + import org.springframework.mail.SimpleMailMessage; + + public class SimpleOrderManager implements OrderManager { + + private MailSender mailSender; + private SimpleMailMessage templateMessage; + + public void setMailSender(MailSender mailSender) { + this.mailSender = mailSender; + } + + public void setTemplateMessage(SimpleMailMessage templateMessage) { + this.templateMessage = templateMessage; + } + + public void placeOrder(Order order) { + + // Do the business calculations... + + // Call the collaborators to persist the order... + + // Create a thread safe "copy" of the template message and customize it + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(order.getCustomer().getEmailAddress()); + msg.setText( + "Dear " + order.getCustomer().getFirstName() + + order.getCustomer().getLastName() + + ", thank you for placing order. Your order number is " + + order.getOrderNumber()); + try { + this.mailSender.send(msg); + } + catch (MailException ex) { + // simply log it and go on... + System.err.println(ex.getMessage()); + } + } + + } +---- + +The following example shows the bean definitions for the preceding code: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + +---- + + +[[mail-usage-mime]] +=== Using `JavaMailSender` and `MimeMessagePreparator` + +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"] +---- + import jakarta.mail.Message; + import jakarta.mail.MessagingException; + import jakarta.mail.internet.InternetAddress; + import jakarta.mail.internet.MimeMessage; + + import jakarta.mail.internet.MimeMessage; + import org.springframework.mail.MailException; + import org.springframework.mail.javamail.JavaMailSender; + import org.springframework.mail.javamail.MimeMessagePreparator; + + public class SimpleOrderManager implements OrderManager { + + private JavaMailSender mailSender; + + public void setMailSender(JavaMailSender mailSender) { + this.mailSender = mailSender; + } + + public void placeOrder(final Order order) { + // Do the business calculations... + // Call the collaborators to persist the order... + + MimeMessagePreparator preparator = new MimeMessagePreparator() { + public void prepare(MimeMessage mimeMessage) throws Exception { + mimeMessage.setRecipient(Message.RecipientType.TO, + new InternetAddress(order.getCustomer().getEmailAddress())); + mimeMessage.setFrom(new InternetAddress("mail@mycompany.example")); + mimeMessage.setText("Dear " + order.getCustomer().getFirstName() + " " + + order.getCustomer().getLastName() + ", thanks for your order. " + + "Your order number is " + order.getOrderNumber() + "."); + } + }; + + try { + this.mailSender.send(preparator); + } + catch (MailException ex) { + // simply log it and go on... + System.err.println(ex.getMessage()); + } + } + + } +---- + +NOTE: The mail code is a crosscutting concern and could well be a candidate for +refactoring into a <>, which could then +be run at appropriate joinpoints on the `OrderManager` target. + +The Spring Framework's mail support ships with the standard JavaMail implementation. +See the relevant javadoc for more information. + + + +[[mail-javamail-mime]] +== Using the JavaMail `MimeMessageHelper` + +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"] +---- + // of course you would use DI in any real-world cases + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + sender.setHost("mail.host.com"); + + MimeMessage message = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message); + helper.setTo("test@host.com"); + helper.setText("Thank you for ordering!"); + + sender.send(message); +---- + + +[[mail-javamail-mime-attachments]] +=== Sending Attachments and Inline Resources + +Multipart email messages allow for both attachments and inline resources. Examples of +inline resources include 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 +with a single JPEG image attachment: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + sender.setHost("mail.host.com"); + + MimeMessage message = sender.createMimeMessage(); + + // use the true flag to indicate you need a multipart message + MimeMessageHelper helper = new MimeMessageHelper(message, true); + helper.setTo("test@host.com"); + + helper.setText("Check out this image!"); + + // let's attach the infamous windows Sample file (this time copied to c:/) + FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg")); + helper.addAttachment("CoolImage.jpg", file); + + sender.send(message); +---- + +[[mail-javamail-mime-attachments-inline]] +==== Inline Resources + +The following example shows you how to use the `MimeMessageHelper` to send an email +with an inline image: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + sender.setHost("mail.host.com"); + + MimeMessage message = sender.createMimeMessage(); + + // use the true flag to indicate you need a multipart message + MimeMessageHelper helper = new MimeMessageHelper(message, true); + helper.setTo("test@host.com"); + + // use the true flag to indicate the text included is HTML + helper.setText("", true); + + // let's include the infamous windows Sample file (this time copied to c:/) + FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg")); + helper.addInline("identifier1234", res); + + sender.send(message); +---- + +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 by Using a Templating Library + +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, developers often do not create the content +of email messages 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. +* Changing the display structure of the email content requires writing Java code, + 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 +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 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. + diff --git a/framework-docs/src/docs/asciidoc/integration/jms.adoc b/framework-docs/src/docs/asciidoc/integration/jms.adoc new file mode 100644 index 0000000000..f7b1c91f76 --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/jms.adoc @@ -0,0 +1,1472 @@ +[[jms]] += JMS (Java Message Service) + +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 Jakarta EE's +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 `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 sending messages, +consuming messages synchronously, and exposing the JMS session and message producer to +the user. + +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 any provider-specific subclasses +of the checked `jakarta.jms.JMSException` exist, this exception is wrapped in the +unchecked `UncategorizedJmsException`. + +The `org.springframework.jms.support.converter` package provides a `MessageConverter` +abstraction to convert between Java objects and JMS messages. + +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 `org.springframework.jms.annotation` package provides the necessary infrastructure +to support annotation-driven listener endpoints by using `@JmsListener`. + +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 `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 +resource into Spring's transaction management mechanisms. + +[NOTE] +==== +As of Spring Framework 5, Spring's JMS package fully supports JMS 2.0 and requires the +JMS 2.0 API to be present at runtime. We recommend the use of a JMS 2.0 compatible provider. + +If you happen to use an older message broker in your system, you may try upgrading to a +JMS 2.0 compatible driver for your existing broker generation. Alternatively, you may also +try to run against a JMS 1.1 based driver, simply putting the JMS 2.0 API jar on the +classpath but only using JMS 1.1 compatible API against your driver. Spring's JMS support +adheres to JMS 1.1 conventions by default, so with corresponding configuration it does +support such a scenario. However, please consider this for transition scenarios only. +==== + + + +[[jms-using]] +== Using Spring JMS + +This section describes how to use Spring's JMS components. + + +[[jms-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 +synchronously receiving messages. + +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 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 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 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 +for sending a message and waiting for a reply on a temporary queue that is created as part of +the operation. + +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. + +As of Spring Framework 4.1, `JmsMessagingTemplate` is built on top of `JmsTemplate` +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]] +=== Connections + +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. + +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 +of connections and sessions. In order to use this implementation, Jakarta EE containers +typically require that you declare a JMS connection factory as a `resource-ref` inside +the EJB or servlet deployment descriptors. To ensure the use of these features with the +`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: + +[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`. + +[[jms-connection-factory]] +==== Using `SingleConnectionFactory` + +Spring provides an implementation of the `ConnectionFactory` interface, +`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]] +==== Using `CachingConnectionFactory` + +The `CachingConnectionFactory` extends the functionality of `SingleConnectionFactory` +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, +noLocal delivery flag, and the durable subscription name (if creating durable consumers). + +[NOTE] +==== +MessageProducers and MessageConsumers for temporary queues and topics +(TemporaryQueue/TemporaryTopic) will never be cached. Unfortunately, WebLogic JMS happens +to implement the temporary queue/topic interfaces on its regular destination implementation, +mis-indicating that none of its destinations can be cached. Please use a different connection +pool/cache on WebLogic, or customize `CachingConnectionFactory` for WebLogic purposes. +==== + + +[[jms-destinations]] +=== Destination Management + +Destinations, as `ConnectionFactory` instances, are JMS administered objects that you can store +and retrieve 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 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 that implements the +`DestinationResolver` interface. `DynamicDestinationResolver` is the default +implementation used by `JmsTemplate` and accommodates resolving dynamic destinations. A +`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 +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 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. +However, a simple implementation choice that is sometimes made by vendors is to +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`, 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 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.) 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 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 specialized feature set. + +* <> +* <> + +[[jms-mdp-simple]] +==== 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 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 Jakarta EE's JMS restrictions. + +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 `Session` instances and, therefore, does not include any other +`Session` operations (such as sending response messages) in the transaction protocol. + +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]] +==== Using `DefaultMessageListenerContainer` + +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`. 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 participation in externally managed +transactions), and compatibility with Jakarta EE environments. + +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 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 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`) 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.). + +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 + +Spring provides a `JmsTransactionManager` that manages transactions for a single JMS +`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 Jakarta 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` 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` +class. + +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 Jakarta 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 +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 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`. + + + +[[jms-sending]] +== Sending a Message + +The `JmsTemplate` contains many convenience methods to send a message. Send +methods specify the destination by using a `jakarta.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"] +---- + import jakarta.jms.ConnectionFactory; + import jakarta.jms.JMSException; + import jakarta.jms.Message; + import jakarta.jms.Queue; + import jakarta.jms.Session; + + import org.springframework.jms.core.MessageCreator; + import org.springframework.jms.core.JmsTemplate; + + public class JmsQueueSender { + + private JmsTemplate jmsTemplate; + private Queue queue; + + public void setConnectionFactory(ConnectionFactory cf) { + this.jmsTemplate = new JmsTemplate(cf); + } + + public void setQueue(Queue queue) { + this.queue = queue; + } + + public void simpleSend() { + this.jmsTemplate.send(this.queue, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("hello queue world"); + } + }); + } + } +---- + +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 +deriving from Spring's `JmsGatewaySupport` convenience base class, which provides +pre-built bean properties for JMS configuration. + +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`. + +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 + +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()` 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 +between `String` and `TextMessage`, `byte[]` and `BytesMessage`, 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 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 +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 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 +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"] +---- + public void sendWithConversion() { + Map map = new HashMap(); + map.put("Name", "Mark"); + map.put("Age", new Integer(47)); + jmsTemplate.convertAndSend("testQueue", map, new MessagePostProcessor() { + public Message postProcessMessage(Message message) throws JMSException { + message.setIntProperty("AccountID", 1234); + message.setJMSCorrelationID("123-00001"); + return message; + } + }); + } +---- + +This results in a message of the following form: + +[literal] +[subs="verbatim,quotes"] +---- +MapMessage={ + Header={ + ... standard headers ... + CorrelationID={123-00001} + } + Properties={ + AccountID={Integer:1234} + } + Fields={ + Name={String:Mark} + Age={Integer:47} + } +} +---- + + +[[jms-callbacks]] +=== Using `SessionCallback` and `ProducerCallback` + +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` run +these callback methods. + + + +[[jms-receiving]] +== Receiving a Message + +This describes how to receive messages with JMS in Spring. + + +[[jms-receiving-sync]] +=== Synchronous Reception + +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 `receiveTimeout` property specifies how long +the receiver should wait before giving up waiting for a message. + + +[[jms-receiving-async]] +=== Asynchronous reception: Message-Driven POJOs + +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 <> 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 +<>) on an MDP is that it must implement +the `jakarta.jms.MessageListener` interface. Note that, if your POJO receives messages +on multiple threads, it is important to ensure that your implementation is thread-safe. + +The following example shows a simple implementation of an MDP: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + import jakarta.jms.JMSException; + import jakarta.jms.Message; + import jakarta.jms.MessageListener; + import jakarta.jms.TextMessage; + + public class ExampleListener implements MessageListener { + + public void onMessage(Message message) { + if (message instanceof TextMessage textMessage) { + try { + System.out.println(textMessage.getText()); + } + catch (JMSException ex) { + throw new RuntimeException(ex); + } + } + else { + throw new IllegalArgumentException("Message must be of type TextMessage"); + } + } + } +---- + +Once you have implemented your `MessageListener`, it is time to create a message listener +container. + +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"] +---- + + + + + + + + + +---- + +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]] +=== Using the `SessionAwareMessageListener` Interface + +The `SessionAwareMessageListener` interface is a Spring-specific interface that provides +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"] +---- + package org.springframework.jms.listener; + + public interface SessionAwareMessageListener { + + 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 (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 +`SessionAwareMessageListener` come with the caveat that they are then tied to Spring +through the interface. The choice of whether or not to use it is left entirely up to you +as an application developer or architect. + +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 thrown exceptions. + + +[[jms-receiving-async-message-listener-adapter]] +=== Using `MessageListenerAdapter` + +The `MessageListenerAdapter` class is the final component in Spring's asynchronous +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: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface MessageDelegate { + + void handleMessage(String message); + + void handleMessage(Map message); + + void handleMessage(byte[] message); + + void handleMessage(Serializable message); + } +---- + +Notice that, although the interface extends neither the `MessageListener` nor the +`SessionAwareMessageListener` interface, you can still use it as an 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"] +---- + public class DefaultMessageDelegate implements MessageDelegate { + // implementation elided for clarity... + } +---- + +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"] +---- + + + + + + + + + + + + + +---- + +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 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 `TextMessageDelegate` interface: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface TextMessageDelegate { + + void receive(TextMessage message); + } +---- + +The following listing shows a class that implements the `TextMessageDelegate` interface: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public class DefaultTextMessageDelegate implements TextMessageDelegate { + // implementation elided for clarity... + } +---- + +The configuration of the attendant `MessageListenerAdapter` would then be as follows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + +---- + +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 following interface and class: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface ResponsiveTextMessageDelegate { + + // notice the return type... + String receive(TextMessage message); + } +---- + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate { + // implementation elided for clarity... + } +---- + +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 + +Invoking a message listener within a transaction requires only reconfiguration of the +listener container. + +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 (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"] +---- + + + + + + +---- + +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 want +to configure a `JtaTransactionManager` (which, by default, delegates to the Jakarta 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 +Jakarta 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 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"] +---- + + + + + <1> + +---- +<1> Our transaction manager. + + + +[[jms-jca-message-endpoint-manager]] +== Support for JCA Message Endpoints + +Beginning with version 2.5, Spring also provides support for a JCA-based +`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 provide +Spring's generic `JmsActivationSpecConfig`, as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +Alternatively, you can set up a `JmsMessageEndpointManager` with a given +`ActivationSpec` object. The `ActivationSpec` object may also come from a JNDI lookup +(using ``). The following example shows how to do so: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + +---- + +Using Spring's `ResourceAdapterFactoryBean`, you can configure the target `ResourceAdapter` +locally, as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + +---- + +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 (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`. + +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 that is not tied to JMS: +`org.springframework.jca.endpoint.GenericMessageEndpointManager`. This component allows +for using any message listener type (such as a JMS `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 + +The easiest way to receive a message asynchronously is to use the annotated listener +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"] +---- + @Component + public class MyService { + + @JmsListener(destination = "myDestination") + public void processOrder(String data) { ... } + } +---- + +The idea of the preceding example is that, whenever a message is available on the +`jakarta.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, by using a `JmsListenerContainerFactory`. +Such a container is not registered against the application context but can be easily +located for management purposes by using the `JmsListenerEndpointRegistry` bean. + +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 + +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"] +---- + @Configuration + @EnableJms + public class AppConfig { + + @Bean + public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + factory.setDestinationResolver(destinationResolver()); + factory.setSessionTransacted(true); + factory.setConcurrency("3-10"); + return factory; + } + } +---- + +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), you can invoke the `processOrder` +method with a core poll size of three threads and a maximum pool size of ten threads. + +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 <>, you can use the `` +element, as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + +---- + + +[[jms-annotated-programmatic-registration]] +=== Programmatic Endpoint Registration + +`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"] +---- + @Configuration + @EnableJms + public class AppConfig implements JmsListenerConfigurer { + + @Override + public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { + SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint(); + endpoint.setId("myJmsEndpoint"); + endpoint.setDestination("anotherQueue"); + endpoint.setMessageListener(message -> { + // processing + }); + registrar.registerEndpoint(endpoint); + } + } +---- + +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`. + + +[[jms-annotated-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. In the following example, we rewrite it to inject the `Order` with +a custom header: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Component + public class MyService { + + @JmsListener(destination = "myDestination") + public void processOrder(Order order, @Header("order_type") String orderType) { + ... + } + } +---- + +The main elements you can inject in JMS listener endpoints are as follows: + +* The raw `jakarta.jms.Message` or any of its subclasses (provided that it + matches the incoming message type). +* The `jakarta.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. +* 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 (`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. 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 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 the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Configuration + @EnableJms + public class AppConfig implements JmsListenerConfigurer { + + @Override + public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { + registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory()); + } + + @Bean + public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() { + DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); + factory.setValidator(myValidator()); + return factory; + } + } +---- + + +[[jms-annotated-response]] +=== Response Management + +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 `jakarta.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. You can now set that default destination by using the `@SendTo` annotation of the +messaging abstraction. + +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"] +---- + @JmsListener(destination = "myDestination") + @SendTo("status") + public OrderStatus processOrder(Order order) { + // order processing + return status; + } +---- + +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 can return a +`Message` instead, with a method similar to the following: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @JmsListener(destination = "myDestination") + @SendTo("status") + public Message processOrder(Order order) { + // order processing + return MessageBuilder + .withPayload(status) + .setHeader("code", 1234) + .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. We can rewrite the previous +example as follows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @JmsListener(destination = "myDestination") + public JmsResponse> processOrder(Order order) { + // order processing + Message response = MessageBuilder + .withPayload(status) + .setHeader("code", 1234) + .build(); + 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, +as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Configuration + @EnableJms + public class AppConfig { + + @Bean + public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + QosSettings replyQosSettings = new QosSettings(); + replyQosSettings.setPriority(2); + replyQosSettings.setTimeToLive(10000); + factory.setReplyQosSettings(replyQosSettings); + return factory; + } + } +---- + + + +[[jms-namespace]] +== JMS Namespace Support + +Spring provides an XML namespace for simplifying JMS configuration. To use the JMS +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 https://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/jms https://www.springframework.org/schema/jms/spring-jms.xsd"> + + + + +---- +<1> Referencing the JMS schema. + + +The namespace consists of three top-level elements: ``, `` +and ``. `` enables the use of <>. `` and `` +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"] +---- + + + + + + + +---- + +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 +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 +[cols="1,6"] +|=== +| Attribute | Description + +| `id` +| A bean name for the hosting listener container. If not specified, a bean name is + automatically generated. + +| `destination` (required) +| The destination name for this listener, resolved through the `DestinationResolver` + strategy. + +| `ref` (required) +| The bean name of the handler object. + +| `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 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` +| The name of the durable subscription, if any. + +| `selector` +| An optional message selector for this listener. + +| `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. By using +these attributes, you can define highly-customized listener containers while +still benefiting from the convenience of the namespace. + +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"] +---- + + + + + + + +---- + +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]] +.Attributes of the JMS element +[cols="1,6"] +|=== +| Attribute | Description + +| `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 a fully qualified class name. + The default is Spring's standard `DefaultMessageListenerContainer` or + `SimpleMessageListenerContainer`, according to the `container-type` attribute. + +| `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. + +| `connection-factory` +| A reference to the JMS `ConnectionFactory` bean (the default bean name is + `connectionFactory`). + +| `task-executor` +| A reference to the Spring `TaskExecutor` for the JMS listener invokers. + +| `destination-resolver` +| A reference to the `DestinationResolver` strategy for resolving JMS `Destination` instances. + +| `message-converter` +| A reference to the `MessageConverter` strategy for converting JMS Messages to listener + method arguments. The default is a `SimpleMessageConverter`. + +| `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 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` or `topic`. The default is the value of the + `destination-type` attribute. + +| `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 is effectively `consumer`, unless + an external transaction manager has been specified -- in which case, the effective + default will be `none` (assuming Jakarta 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, you can specify + the `transaction-manager` attribute, described later in table. The default is `auto`. + +| `transaction-manager` +| A reference to an external `PlatformTransactionManager` (typically an XA-based + 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` +| The maximum number of messages to load into a single session. Note that raising this + number might lead to starvation of concurrent consumers. + +| `receive-timeout` +| The timeout (in milliseconds) to use for receive calls. The default is `1000` (one + second). `-1` indicates no timeout. + +| `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 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 milliseconds (that is, five seconds). + +| `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 milliseconds + (that is, five seconds). + +| `phase` +| The lifecycle phase within which this container should start and stop. The lower the + 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, +as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + +---- + +The following table describes the available configuration options for the JCA variant: + +[[jms-namespace-jca-listener-container-tbl]] +.Attributes of the JMS element +[cols="1,6"] +|=== +| Attribute | Description + +| `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. + +| `resource-adapter` +| A reference to the JCA `ResourceAdapter` bean (the default bean name is + `resourceAdapter`). + +| `activation-spec-factory` +| A reference to the `JmsActivationSpecFactory`. The default is to autodetect the JMS + provider and its `ActivationSpec` class (see {api-spring-framework}/jms/listener/endpoint/DefaultJmsActivationSpecFactory.html[`DefaultJmsActivationSpecFactory`]). + +| `destination-resolver` +| A reference to the `DestinationResolver` strategy for resolving JMS `Destinations`. + +| `message-converter` +| A reference to the `MessageConverter` strategy for converting JMS Messages to listener + method arguments. The default is `SimpleMessageConverter`. + +| `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` or `topic`. The default is the value of the + `destination-type` attribute. + +| `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, you can specify + the `transaction-manager` attribute described later. The default is `auto`. + +| `transaction-manager` +| A reference to a Spring `JtaTransactionManager` or a + `jakarta.transaction.TransactionManager` for kicking off an XA transaction for each + incoming message. 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 only a + hint and is typically ignored at runtime when you use a JCA listener container. + The default is 1. + +| `prefetch` +| The maximum number of messages to load into a single session. Note that raising this + number might lead to starvation of concurrent consumers. +|=== diff --git a/framework-docs/src/docs/asciidoc/integration/jmx.adoc b/framework-docs/src/docs/asciidoc/integration/jmx.adoc new file mode 100644 index 0000000000..31a27d567a --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/jmx.adoc @@ -0,0 +1,1375 @@ +[[jmx]] += JMX + +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 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. + +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 +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 + +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"] +---- + package org.springframework.jmx; + + public class JmxTestBean implements IJmxTestBean { + + private String name; + private int age; + private boolean isSuperman; + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public int add(int x, int y) { + return x + y; + } + + public void dontExposeMe() { + throw new RuntimeException(); + } + } +---- + +To expose the properties and methods of this bean as attributes and operations of an +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"] +---- + + + + + + + + + + + + + + +---- + +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. 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 (except those inherited from the +`Object` class) are exposed as operations. + +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 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 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 +`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` instance's `server` property to the `MBeanServer` value returned by an +`MBeanServerFactoryBean`, as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + +---- + +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. + + +[[jmx-mbean-server]] +=== Reusing an Existing `MBeanServer` + +If no server is specified, the `MBeanExporter` tries to automatically detect a running +`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"] +---- + + + + + + + + + + ... + + +---- + +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"] +---- + + + + + + + + + + + +---- + + +[[jmx-exporting-lazy]] +=== Lazily Initialized MBeans + +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 + +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. 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"] +---- + + + + + +---- + +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 <>. + + +[[jmx-exporting-registration-behavior]] +=== Controlling the Registration Behavior + +Consider the scenario where a Spring `MBeanExporter` attempts to register 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`). + +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`. +The following table summarizes these registration behaviors: + +[[jmx-registration-behaviors]] +.Registration Behaviors +[cols="1,4"] +|=== +| Registration behavior | Explanation + +| `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 is not + registered, and an `InstanceAlreadyExistsException` is thrown. The existing + `MBean` is unaffected. + +| `IGNORE_EXISTING` +| If an `MBean` instance has already been registered under the same `ObjectName`, the + `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`. + +| `REPLACE_EXISTING` +| If an `MBean` instance has already been registered under the same `ObjectName`, 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 values in the preceding table are defined as enums on the `RegistrationPolicy` class. +If you want to change the default registration behavior, you need to set the value of the +`registrationPolicy` property on your `MBeanExporter` definition to one of those +values. + +The following example shows how to change from the default registration +behavior to the `REPLACE_EXISTING` behavior: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + +---- + + + +[[jmx-interface]] +== Controlling the Management Interface of Your Beans + +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]] +=== 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 exposed. +The default implementation, +`org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler`, +defines a management interface that exposes all public properties and methods +(as you 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 + +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 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. 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. + +NOTE: A `ManagedResource`-annotated bean must be public, as must the methods exposing +an operation or an attribute. + +The following example shows the annotated version of the `JmxTestBean` class that we +used in <>: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + package org.springframework.jmx; + + import org.springframework.jmx.export.annotation.ManagedResource; + import org.springframework.jmx.export.annotation.ManagedOperation; + import org.springframework.jmx.export.annotation.ManagedAttribute; + + @ManagedResource( + objectName="bean:name=testBean4", + description="My Managed Bean", + log=true, + logFile="jmx.log", + currencyTimeLimit=15, + persistPolicy="OnUpdate", + persistPeriod=200, + persistLocation="foo", + persistName="bar") + public class AnnotationTestBean implements IJmxTestBean { + + private String name; + private int age; + + @ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15) + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @ManagedAttribute(description="The Name Attribute", + currencyTimeLimit=20, + defaultValue="bar", + persistPolicy="OnUpdate") + public void setName(String name) { + this.name = name; + } + + @ManagedAttribute(defaultValue="foo", persistPeriod=300) + public String getName() { + return name; + } + + @ManagedOperation(description="Add two numbers") + @ManagedOperationParameters({ + @ManagedOperationParameter(name = "x", description = "The first number"), + @ManagedOperationParameter(name = "y", description = "The second number")}) + public int add(int x, int y) { + return x + y; + } + + public void dontExposeMe() { + throw new RuntimeException(); + } + + } +---- + +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 <>. + +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, 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 following configuration shows how you can configure the `MBeanExporter` to use the +`MetadataMBeanInfoAssembler`: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + + + + + +---- + +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 + +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. +| `@ManagedResource` +| Class + +| Mark a method as a JMX operation. +| `@ManagedOperation` +| Method + +| Mark a getter or setter as one half of a JMX attribute. +| `@ManagedAttribute` +| Method (only getters and setters) + +| Define descriptions for operation parameters. +| `@ManagedOperationParameter` and `@ManagedOperationParameters` +| Method +|=== + +The following table describes the configuration parameters that are available for use on these source-level +metadata types: + +[[jmx-metadata-parameters]] +.Source-level metadata parameters +[cols="1,3,1"] +|=== +| Parameter | Description | Applies to + +| `ObjectName` +| 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`, or `ManagedOperationParameter` + +| `currencyTimeLimit` +| Sets the value of the `currencyTimeLimit` descriptor field. +| `ManagedResource` or `ManagedAttribute` + +| `defaultValue` +| Sets the value of the `defaultValue` descriptor field. +| `ManagedAttribute` + +| `log` +| Sets the value of the `log` descriptor field. +| `ManagedResource` + +| `logFile` +| Sets the value of the `logFile` descriptor field. +| `ManagedResource` + +| `persistPolicy` +| Sets the value of the `persistPolicy` descriptor field. +| `ManagedResource` + +| `persistPeriod` +| Sets the value of the `persistPeriod` descriptor field. +| `ManagedResource` + +| `persistLocation` +| Sets the value of the `persistLocation` descriptor field. +| `ManagedResource` + +| `persistName` +| Sets the value of the `persistName` descriptor field. +| `ManagedResource` + +| `name` +| Sets the display name of an operation parameter. +| `ManagedOperationParameter` + +| `index` +| Sets the index of an operation parameter. +| `ManagedOperationParameter` +|=== + + +[[jmx-interface-autodetect]] +=== Using the `AutodetectCapableMBeanInfoAssembler` Interface + +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`, it is +allowed to "`vote`" on the inclusion of beans for exposure to JMX. + +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 similar to the following: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + +---- + +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 by Using Java Interfaces + +In addition to the `MetadataMBeanInfoAssembler`, Spring also includes the +`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, `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 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"] +---- + public interface IJmxTestBean { + + public int add(int x, int y); + + public long myOperation(); + + public int getAge(); + + public void setAge(int age); + + public void setName(String name); + + public String getName(); + + } +---- + +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"] +---- + + + + + + + + + + + + org.springframework.jmx.IJmxTestBean + + + + + + + + + + + +---- + +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 +interface. + +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 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, 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` + +`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"] +---- + + + + + + + + + + add,myOperation,getName,setName,getAge + + + + +---- + +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 `ObjectName` Instances for Your Beans + +Behind the scenes, the `MBeanExporter` delegates to an implementation 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` (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 `ObjectName` Instances from Properties + +You can configure your own `KeyNamingStrategy` instance and configure it to read +`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 following code shows a sample configuration for the `KeyNamingStrategy`: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + bean:name=testBean1 + + + + names1.properties,names2.properties + + + + +---- + +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 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, the bean key name is used as +the `ObjectName`. + + +[[jmx-naming-metadata]] +=== Using `MetadataNamingStrategy` + +`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"] +---- + + + + + + + + + + + + + + + + + + + + + + + +---- + +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 + +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, +as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Configuration + @EnableMBeanExport + public class AppConfig { + + } +---- + +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"] +---- + +---- + +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 `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"] +---- + @EnableMBeanExport(server="myMBeanServer", defaultDomain="myDomain") + @Configuration + ContextConfiguration { + + } +---- + +The following example shows the XML equivalent of the preceding annotation-based example: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + +---- + +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]] +== 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 +connectors. + + +[[jmx-jsr160-server]] +=== Server-side Connectors + +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 +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, +the main open-source JMX implementation, MX4J, and the one provided with the JDK +do not support JMXMP. + +To specify another URL and register the `JMXConnectorServer` itself with the +`MBeanServer`, you can use the `serviceUrl` and `ObjectName` properties, respectively, +as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + +---- + +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"] +---- + + + + + + + + + + + +---- + +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. + + +[[jmx-jsr160-client]] +=== Client-side Connectors + +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"] +---- + + + +---- + + +[[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 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 such as SOAP or Hessian over simple HTTP or SSL and others, +as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + +---- + +In the preceding example, we used MX4J 3.0.0. See the official MX4J +documentation for more information. + + + +[[jmx-proxy]] +== Accessing MBeans through Proxies + +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"] +---- + + + + +---- + +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 through an +`MBeanServerConnection`. By default, the local `MBeanServer` is located and used, but +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"] +---- + + + + + + + + + +---- + +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`. + + + +[[jmx-notifications]] +== Notifications + +Spring's JMX offering includes comprehensive support for JMX notifications. + + +[[jmx-notifications-listeners]] +=== Registering Listeners for Notifications + +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 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"] +---- + package com.example; + + import javax.management.AttributeChangeNotification; + import javax.management.Notification; + import javax.management.NotificationFilter; + import javax.management.NotificationListener; + + public class ConsoleLoggingNotificationListener + implements NotificationListener, NotificationFilter { + + public void handleNotification(Notification notification, Object handback) { + System.out.println(notification); + System.out.println(handback); + } + + public boolean isNotificationEnabled(Notification notification) { + return AttributeChangeNotification.class.isAssignableFrom(notification.getClass()); + } + + } +---- + +The following example adds `ConsoleLoggingNotificationListener` (defined in the preceding +example) to `notificationListenerMappings`: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + + + + +---- + +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, +as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + + + + +---- + +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"] +---- + + + + + + + +---- + +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 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 +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, as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + bean:name=testBean1 + + + + + + + + + + + + + +---- + +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"] +---- + + + + + + + + + + + + + + + + + bean:name=testBean1 + bean:name=testBean2 + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +(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 only for registering to receive `Notifications` but also +for publishing `Notifications`. + +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 through an `MBeanExporter` instance can implement the related +`NotificationPublisherAware` interface to gain access to a `NotificationPublisher` +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 javadoc of the +{api-spring-framework}/jmx/export/notification/NotificationPublisher.html[`NotificationPublisher`] +interface, managed beans that publish events through the `NotificationPublisher` +mechanism are not responsible for the state management of 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. You create a JMX +`Notification` instance (or an instance of an appropriate `Notification` 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`. + +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"] +---- + package org.springframework.jmx; + + import org.springframework.jmx.export.notification.NotificationPublisherAware; + import org.springframework.jmx.export.notification.NotificationPublisher; + import javax.management.Notification; + + public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware { + + private String name; + private int age; + private boolean isSuperman; + private NotificationPublisher publisher; + + // other getters and setters omitted for clarity + + public int add(int x, int y) { + int answer = x + y; + this.publisher.sendNotification(new Notification("add", this, 0)); + return answer; + } + + public void dontExposeMe() { + throw new RuntimeException(); + } + + public void setNotificationPublisher(NotificationPublisher notificationPublisher) { + this.publisher = notificationPublisher; + } + + } +---- + +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 +you can accept the coupling to both Spring and JMX, then do so. + + + +[[jmx-resources]] +== Further Resources + +This section contains links to further resources about JMX: + +* The https://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX +homepage] at Oracle. +* The https://jcp.org/aboutJava/communityprocess/final/jsr003/index3.html[JMX + specification] (JSR-000003). +* The https://jcp.org/aboutJava/communityprocess/final/jsr160/index.html[JMX Remote API + specification] (JSR-000160). +* The http://mx4j.sourceforge.net/[MX4J homepage]. (MX4J is an open-source implementation of + various JMX specs.) + diff --git a/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc b/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc new file mode 100644 index 0000000000..44dc60cd9b --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/rest-clients.adoc @@ -0,0 +1,517 @@ +[[rest-client-access]] += REST Clients + +The Spring Framework provides the following choices for making calls to REST endpoints: + +* <> - non-blocking, reactive client w fluent API. +* <> - synchronous client with template method API. +* <> - annotated interface with generated, dynamic proxy implementation. + + +[[rest-webclient]] +== `WebClient` + +`WebClient` is a non-blocking, reactive client to perform HTTP requests. It was +introduced in 5.0 and offers an alternative to the `RestTemplate`, with support for +synchronous, asynchronous, and streaming scenarios. + +`WebClient` supports the following: + +* Non-blocking I/O. +* Reactive Streams back pressure. +* High concurrency with fewer hardware resources. +* Functional-style, fluent API that takes advantage of Java 8 lambdas. +* Synchronous and asynchronous interactions. +* Streaming up to or streaming down from a server. + +See <> for more details. + + + + +[[rest-resttemplate]] +== `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 +overloaded methods: + +NOTE: `RestTemplate` is in maintenance mode, with only requests for minor +changes and bugs to be accepted. Please, consider using the +<> instead. + +[[rest-overview-of-resttemplate-methods-tbl]] +.RestTemplate methods +[cols="1,3"] +|=== +| Method group | Description + +| `getForObject` +| Retrieves a representation via GET. + +| `getForEntity` +| Retrieves a `ResponseEntity` (that is, status, headers, and body) by using GET. + +| `headForHeaders` +| Retrieves all headers for a resource by using HEAD. + +| `postForLocation` +| Creates a new resource by using POST and returns the `Location` header from the response. + +| `postForObject` +| Creates a new resource by using POST and returns the representation from the response. + +| `postForEntity` +| Creates a new resource by using POST and returns the representation from the response. + +| `put` +| Creates or updates a resource by using PUT. + +| `patchForObject` +| Updates a resource by using PATCH and returns the representation from the response. +Note that the JDK `HttpURLConnection` does not support `PATCH`, but Apache +HttpComponents and others do. + +| `delete` +| Deletes the resources at the specified URI by using DELETE. + +| `optionsForAllow` +| Retrieves allowed HTTP methods for a resource by using ALLOW. + +| `exchange` +| 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 through callback interfaces. + +|=== + +[[rest-resttemplate-create]] +=== Initialization + +The default constructor uses `java.net.HttpURLConnection` to perform requests. You can +switch to a different HTTP library with an implementation of `ClientHttpRequestFactory`. +There is built-in support for the following: + +* Apache HttpComponents +* Netty +* OkHttp + +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 -- for example, for credentials, connection pooling, and other details. + +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 accept a URI template and URI template variables, +either as a `String` variable argument, or as `Map`. + +The following example uses a `String` variable argument: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + String result = restTemplate.getForObject( + "https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21"); +---- + +The following example uses a `Map`: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + Map vars = Collections.singletonMap("hotel", "42"); + + String result = restTemplate.getForObject( + "https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); +---- + +Keep in mind URI templates are automatically encoded, as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + restTemplate.getForObject("https://example.com/hotel list", String.class); + + // Results in request to "https://example.com/hotel%20list" +---- + +You can use the `uriTemplateHandler` property of `RestTemplate` to customize how URIs +are 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 + +You can use the `exchange()` methods to specify request headers, as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + String uriTemplate = "https://example.com/hotels/{hotel}"; + URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42); + + RequestEntity requestEntity = RequestEntity.get(uri) + .header("MyRequestHeader", "MyValue") + .build(); + + ResponseEntity response = template.exchange(requestEntity, String.class); + + String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); + String body = response.getBody(); +---- + +You can obtain response headers through many `RestTemplate` method variants that return +`ResponseEntity`. + +[[rest-template-body]] +=== Body + +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, as the following example shows: + +---- +URI location = template.postForLocation("https://example.com/people", person); +---- + +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`, as the following example shows: + +---- +Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42); +---- + +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. + +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]#<># + +The `spring-web` module contains the `HttpMessageConverter` contract for reading and +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, by default, registered with the `RestTemplate` on the client side and with +`RequestMappingHandlerAdapter` on the server side (see +<>). + +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 +[cols="1,3"] +|=== +| MessageConverter | Description + +| `StringHttpMessageConverter` +| 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 +`application/x-www-form-urlencoded` media type. Form data is read from and written into a +`MultiValueMap`. The converter can also write (but not read) multipart +data read from a `MultiValueMap`. By default, `multipart/form-data` is +supported. As of Spring Framework 5.2, additional multipart subtypes can be supported for +writing form data. Consult the javadoc for `FormHttpMessageConverter` for further details. + +| `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`. You can override this +by setting the `supportedMediaTypes` property and overriding `getContentType(byte[])`. + +| `MarshallingHttpMessageConverter` +| 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. 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 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 by using +https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's +`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`. + +| `BufferedImageHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write +`java.awt.image.BufferedImage` from the HTTP request and response. This converter reads +and writes the media type supported by the Java I/O API. + +|=== + +[[rest-template-jsonview]] +=== Jackson JSON Views + +You can specify a https://www.baeldung.com/jackson-json-view-annotation[Jackson JSON View] +to serialize only a subset of the object properties, as the following example shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23")); + value.setSerializationView(User.WithoutPasswordView.class); + + RequestEntity requestEntity = + RequestEntity.post(new URI("https://example.com/user")).body(value); + + ResponseEntity response = template.exchange(requestEntity, String.class); +---- + +[[rest-template-multipart]] +=== Multipart + +To send multipart data, you need to provide a `MultiValueMap` whose values +may be an `Object` for part content, a `Resource` for a file part, or an `HttpEntity` for +part content with headers. For example: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + MultiValueMap parts = new LinkedMultiValueMap<>(); + + parts.add("fieldPart", "fieldValue"); + parts.add("filePart", new FileSystemResource("...logo.png")); + parts.add("jsonPart", new Person("Jason")); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_XML); + parts.add("xmlPart", new HttpEntity<>(myBean, headers)); +---- + +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` with an `HttpEntity` wrapper. + +Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as show below: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + MultiValueMap parts = ...; + template.postForObject("https://example.com/upload", parts, Void.class); +---- + +If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set +to `multipart/form-data` by the `FormHttpMessageConverter`. If the `MultiValueMap` has +`String` values the `Content-Type` is defaulted to `application/x-www-form-urlencoded`. +If necessary the `Content-Type` may also be set explicitly. + + +[[rest-http-interface]] +== HTTP Interface + +The Spring Framework lets you define an HTTP service as a Java interface with annotated +methods for HTTP exchanges. You can then generate a proxy that implements this interface +and performs the exchanges. This helps to simplify HTTP remote access which often +involves a facade that wraps the details of using the underlying HTTP client. + +One, declare an interface with `@HttpExchange` methods: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + interface RepositoryService { + + @GetExchange("/repos/{owner}/{repo}") + Repository getRepository(@PathVariable String owner, @PathVariable String repo); + + // more HTTP exchange methods... + + } +---- + +Two, create a proxy that will perform the declared HTTP exchanges: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build(); + HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build(); + + RepositoryService service = factory.createClient(RepositoryService.class); +---- + +`@HttpExchange` is supported at the type level where it applies to all methods: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json") + interface RepositoryService { + + @GetExchange + Repository getRepository(@PathVariable String owner, @PathVariable String repo); + + @PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + void updateRepository(@PathVariable String owner, @PathVariable String repo, + @RequestParam String name, @RequestParam String description, @RequestParam String homepage); + + } +---- + + +[[rest-http-interface-method-parameters]] +=== Method Parameters + +Annotated, HTTP exchange methods support flexible method signatures with the following +method parameters: + +[cols="1,2", options="header"] +|=== +| Method argument | Description + +| `URI` +| Dynamically set the URL for the request, overriding the annotation's `url` attribute. + +| `HttpMethod` +| Dynamically set the HTTP method for the request, overriding the annotation's `method` attribute + +| `@RequestHeader` +| Add a request header or mutliple headers. The argument may be a `Map` or + `MultiValueMap` with multiple headers, a `Collection` of values, or an + individual value. Type conversion is supported for non-String values. + +| `@PathVariable` +| Add a variable for expand a placeholder in the request URL. The argument may be a + `Map` with multiple variables, or an individual value. Type conversion + is supported for non-String values. + +| `@RequestBody` +| Provide the body of the request either as an Object to be serialized, or a + Reactive Streams `Publisher` such as `Mono`, `Flux`, or any other async type supported + through the configured `ReactiveAdapterRegistry`. + +| `@RequestParam` +| Add a request parameter or mutliple parameters. The argument may be a `Map` + or `MultiValueMap` with multiple parameters, a `Collection` of values, or + an individual value. Type conversion is supported for non-String values. + + When `"content-type"` is set to `"application/x-www-form-urlencoded"`, request + parameters are encoded in the request body. Otherwise, they are added as URL query + parameters. + +| `@RequestPart` +| Add a request part, which may be a String (form field), `Resource` (file part), + Object (entity to be encoded, e.g. as JSON), `HttpEntity` (part content and headers), + a Spring `Part`, or Reactive Streams `Publisher` of any of the above. + +| `@CookieValue` +| Add a cookie or mutliple cookies. The argument may be a `Map` or + `MultiValueMap` with multiple cookies, a `Collection` of values, or an + individual value. Type conversion is supported for non-String values. + +|=== + + +[[rest-http-interface-return-values]] +=== Return Values + +Annotated, HTTP exchange methods support the following return values: + +[cols="1,2", options="header"] +|=== +| Method return value | Description + +| `void`, `Mono` +| Perform the given request, and release the response content, if any. + +| `HttpHeaders`, `Mono` +| Perform the given request, release the response content, if any, and return the + response headers. + +| ``, `Mono` +| Perform the given request and decode the response content to the declared return type. + +| ``, `Flux` +| Perform the given request and decode the response content to a stream of the declared + element type. + +| `ResponseEntity`, `Mono>` +| Perform the given request, and release the response content, if any, and return a + `ResponseEntity` with the status and headers. + +| `ResponseEntity`, `Mono>` +| Perform the given request, decode the response content to the declared return type, and + return a `ResponseEntity` with the status, headers, and the decoded body. + +| `Mono>` +| Perform the given request, decode the response content to a stream of the declared + element type, and return a `ResponseEntity` with the status, headers, and the decoded + response body stream. + +|=== + +TIP: You can also use any other async or reactive types registered in the +`ReactiveAdapterRegistry`. + + +[[rest-http-interface-exceptions]] +=== Exception Handling + +By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status +codes. To customize this, you can register a response status handler that applies to all +responses performed through the client: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + WebClient webClient = WebClient.builder() + .defaultStatusHandler(HttpStatusCode::isError, resp -> ...) + .build(); + + WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient); + HttpServiceProxyFactory factory = HttpServiceProxyFactory + .builder(clientAdapter).build(); +---- + +For more details and options, such as suppressing error status codes, see the Javadoc of +`defaultStatusHandler` in `WebClient.Builder`. diff --git a/framework-docs/src/docs/asciidoc/integration/scheduling.adoc b/framework-docs/src/docs/asciidoc/integration/scheduling.adoc new file mode 100644 index 0000000000..0c71389c34 --- /dev/null +++ b/framework-docs/src/docs/asciidoc/integration/scheduling.adoc @@ -0,0 +1,967 @@ +[[scheduling]] += Task Execution and Scheduling + +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 +implementations behind the common interfaces abstracts away the differences between Java +SE 5, Java SE 6, and Jakarta EE environments. + +Spring also features integration classes to support scheduling with the `Timer` +(part of the JDK since 1.3) and the Quartz Scheduler ( https://www.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 lets you invoke a method of +an existing target object (analogous to the normal `MethodInvokingFactoryBean` +operation). + + + +[[scheduling-task-executor]] +== The Spring `TaskExecutor` Abstraction + +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 the Java SE and Jakarta 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 +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, you can also use this abstraction for your own needs. + + +[[scheduling-task-executor-types]] +=== `TaskExecutor` Types + +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`: + This implementation does not run 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 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`, 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` + configuration parameters as bean properties. There is rarely a need to use + `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`, we + recommend that you use a `ConcurrentTaskExecutor` instead. +* `DefaultManagedTaskExecutor`: + This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236 + compatible runtime environment (such as a Jakarta EE application server), + replacing a CommonJ WorkManager for that purpose. + + +[[scheduling-task-executor-usage]] +=== Using a `TaskExecutor` + +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"] +---- + import org.springframework.core.task.TaskExecutor; + + public class TaskExecutorExample { + + private class MessagePrinterTask implements Runnable { + + private String message; + + public MessagePrinterTask(String message) { + this.message = message; + } + + public void run() { + System.out.println(message); + } + } + + private TaskExecutor taskExecutor; + + public TaskExecutorExample(TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + } + + public void printMessages() { + for(int i = 0; i < 25; i++) { + taskExecutor.execute(new MessagePrinterTask("Message" + i)); + } + } + } +---- + +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 run. + +To configure the rules that the `TaskExecutor` uses, we expose simple bean properties: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + + + + + +---- + + + +[[scheduling-task-scheduler]] +== The Spring `TaskScheduler` Abstraction + +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"] +---- + public interface TaskScheduler { + + ScheduledFuture schedule(Runnable task, Trigger trigger); + + ScheduledFuture schedule(Runnable task, Instant startTime); + + ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period); + + ScheduledFuture scheduleAtFixedRate(Runnable task, Duration period); + + ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay); + + ScheduledFuture scheduleWithFixedDelay(Runnable task, Duration delay); + +---- + +The simplest method is the one named `schedule` that takes only a `Runnable` and an `Instant`. +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 +much more flexible. + + +[[scheduling-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, as the following listing shows: + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface Trigger { + + Date nextExecutionTime(TriggerContext triggerContext); + } +---- + +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). The following listing shows the available methods for `Trigger` implementations. + +[source,java,indent=0,subs="verbatim,quotes"] +---- + public interface TriggerContext { + + Date lastScheduledExecutionTime(); + + Date lastActualExecutionTime(); + + Date lastCompletionTime(); + } +---- + + +[[scheduling-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 +<>. +For 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 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 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 you can configure such `Triggers` +externally and, therefore, easily modify or extend them. + + +[[scheduling-task-scheduler-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` +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 Jakarta EE 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 +through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a +`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. + + + +[[scheduling-annotation-support]] +== Annotation Support for Scheduling and Asynchronous Execution + +Spring provides annotation support for both task scheduling and asynchronous method +execution. + + +[[scheduling-enable-annotation-support]] +=== Enable Scheduling Annotations + +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"] +---- + @Configuration + @EnableAsync + @EnableScheduling + public class AppConfig { + } +---- + +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, you can use the `` element, +as the following example shows: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + +---- + +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 +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. + + +[[scheduling-annotation-support-scheduled]] +=== The `@Scheduled` annotation + +You can add the `@Scheduled` annotation to a method, along with trigger metadata. For +example, the following method is invoked every five seconds (5000 milliseconds) 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"] +---- + @Scheduled(fixedDelay = 5000) + public void doSomething() { + // something that should run periodically + } +---- + +[NOTE] +==== +By default, milliseconds will be used as the time unit for fixed delay, fixed rate, and +initial delay values. If you would like to use a different time unit such as seconds or +minutes, you can configure this via the `timeUnit` attribute in `@Scheduled`. + +For example, the previous example can also be written as follows. + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS) + public void doSomething() { + // something that should run periodically + } +---- +==== + +If you need a fixed-rate execution, you can use the `fixedRate` attribute 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"] +---- + @Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS) + public void doSomething() { + // something that should run periodically + } +---- + +For fixed-delay and fixed-rate tasks, you can specify an initial delay by indicating the +amount of time to wait before the first execution of the method, as the following +`fixedRate` example shows. + +[source,java,indent=0,subs="verbatim,quotes"] +---- + @Scheduled(initialDelay = 1000, fixedRate = 5000) + public void doSomething() { + // something that should run periodically + } +---- + +If simple periodic scheduling is not expressive enough, you can provide a +<>. +The following example runs only on weekdays: + +[source,java,indent=0] +[subs="verbatim"] +---- + @Scheduled(cron="*/5 * * * * MON-FRI") + public void doSomething() { + // something that should run on weekdays only + } +---- + +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 accept any +arguments. If the method needs to interact with other objects from the application +context, those would typically have been provided through dependency injection. + +[NOTE] +==== +As of Spring Framework 4.3, `@Scheduled` methods are supported on beans of any scope. + +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 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 + +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"] +---- + @Async + void doSomething() { + // this will be run asynchronously + } +---- + +Unlike the methods annotated with the `@Scheduled` annotation, these methods can expect +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"] +---- + @Async + void doSomething(String s) { + // this will be run 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 +asynchronous execution so that the caller can perform other tasks prior to calling +`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"] +---- + @Async + Future returnSomething(int i) { + // this will be run asynchronously + } +---- + +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 +asynchronous task and for immediate composition with further processing steps. + +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"] +---- + public class SampleBeanImpl implements SampleBean { + + @Async + void doSomething() { + // ... + } + + } + + public class SampleBeanInitializer { + + private final SampleBean bean; + + public SampleBeanInitializer(SampleBean bean) { + this.bean = bean; + } + + @PostConstruct + public void initialize() { + bean.doSomething(); + } + + } +---- + +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` + +By default, when specifying `@Async` on a method, the executor that is used is the +one <>, +i.e. the "`annotation-driven`" element if you are using XML or your `AsyncConfigurer` +implementation, if any. 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"] +---- + @Async("otherExecutor") + void doSomething(String s) { + // this will be run 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). + + +[[scheduling-annotation-support-exception]] +=== 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 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"] +---- + public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { + + @Override + public void handleUncaughtException(Throwable ex, Method method, Object... params) { + // handle exception + } + } +---- + +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 + +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 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 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 following creates a `ThreadPoolTaskExecutor` instance: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + +---- + +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 one thing, the thread pool for +a `ThreadPoolTaskExecutor` is itself more configurable. 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"] +---- + +---- + +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, see the documentation for +https://docs.oracle.com/javase/8/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, 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, +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, 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 +when using an unbounded queue). + +Consider the case, as mentioned above, when a task is rejected. By default, when a +task is rejected, 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, 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 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"] +---- + +---- + +Finally, the `keep-alive` setting determines the time limit (in seconds) for which threads +may remain idle before being stopped. 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 get stopped. A time value of zero causes excess threads to stop +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"] +---- + +---- + + +[[scheduling-task-namespace-scheduled-tasks]] +=== 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. The following listing shows a simple example: + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + + + + + +---- + +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 run 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 +to provide a <>. +The following example shows these other options: + +[source,xml,indent=0] +[subs="verbatim"] +---- + + + + + + + +---- + + + +[[scheduling-cron-expression]] +== Cron Expressions + +All Spring cron expressions have to conform to the same format, whether you are using them in +<>, +<>, +or someplace else. +A well-formed cron expression, such as `* * * * * *`, consists of six space-separated time and date +fields, each with its own range of valid values: + + +.... + ┌───────────── second (0-59) + │ ┌───────────── minute (0 - 59) + │ │ ┌───────────── hour (0 - 23) + │ │ │ ┌───────────── day of the month (1 - 31) + │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC) + │ │ │ │ │ ┌───────────── day of the week (0 - 7) + │ │ │ │ │ │ (0 or 7 is Sunday, or MON-SUN) + │ │ │ │ │ │ + * * * * * * +.... + +There are some rules that apply: + +* A field may be an asterisk (`*`), which always stands for "`first-last`". +For the day-of-the-month or day-of-the-week fields, a question mark (`?`) may be used instead of an +asterisk. +* Commas (`,`) are used to separate items of a list. +* Two numbers separated with a hyphen (`-`) express a range of numbers. +The specified range is inclusive. +* Following a range (or `*`) with `/` specifies the interval of the number's value through the range. +* English names can also be used for the month and day-of-week fields. +Use the first three letters of the particular day or month (case does not matter). +* The day-of-month and day-of-week fields can contain a `L` character, which has a different meaning +** In the day-of-month field, `L` stands for _the last day of the month_. +If followed by a negative offset (that is, `L-n`), it means _``n``th-to-last day of the month_. +** In the day-of-week field, `L` stands for _the last day of the week_. +If prefixed by a number or three-letter name (`dL` or `DDDL`), it means _the last day of week (`d` +or `DDD`) in the month_. +* The day-of-month field can be `nW`, which stands for _the nearest weekday to day of the month ``n``_. +If `n` falls on Saturday, this yields the Friday before it. +If `n` falls on Sunday, this yields the Monday after, which also happens if `n` is `1` and falls on +a Saturday (that is: `1W` stands for _the first weekday of the month_). +* If the day-of-month field is `LW`, it means _the last weekday of the month_. +* The day-of-week field can be `d#n` (or `DDD#n`), which stands for _the ``n``th day of week `d` +(or ``DDD``) in the month_. + +Here are some examples: + +|=== +| Cron Expression | Meaning + +|`0 0 * * * *` | top of every hour of every day +|`*/10 * * * * *` | every ten seconds +| `0 0 8-10 * * *` | 8, 9 and 10 o'clock of every day +| `0 0 6,19 * * *` | 6:00 AM and 7:00 PM every day +| `0 0/30 8-10 * * *` | 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day +| `0 0 9-17 * * MON-FRI`| on the hour nine-to-five weekdays +| `0 0 0 25 DEC ?` | every Christmas Day at midnight +| `0 0 0 L * *` | last day of the month at midnight +| `0 0 0 L-3 * *` | third-to-last day of the month at midnight +| `0 0 0 * * 5L` | last Friday of the month at midnight +| `0 0 0 * * THUL` | last Thursday of the month at midnight +| `0 0 0 1W * *` | first weekday of the month at midnight +| `0 0 0 LW * *` | last weekday of the month at midnight +| `0 0 0 ? * 5#2` | the second Friday in the month at midnight +| `0 0 0 ? * MON#1` | the first Monday in the month at midnight +|=== + +=== Macros + +Expressions such as `0 0 * * * *` are hard for humans to parse and are, therefore, hard to fix in case of bugs. +To improve readability, Spring supports the following macros, which represent commonly used sequences. +You can use these macros instead of the six-digit value, thus: `@Scheduled(cron = "@hourly")`. + +|=== +|Macro | Meaning + +| `@yearly` (or `@annually`) | once a year (`0 0 0 1 1 *`) +| `@monthly` | once a month (`0 0 0 1 * *`) +| `@weekly` | once a week (`0 0 0 * * 0`) +| `@daily` (or `@midnight`) | once a day (`0 0 0 * * *`), or +| `@hourly` | once an hour, (`0 0 * * * *`) +|=== + + + +[[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, see +https://www.quartz-scheduler.org/[]. For convenience purposes, Spring offers a couple of +classes that simplify using Quartz within Spring-based applications. + + +[[scheduling-quartz-jobdetail]] +=== Using the `JobDetailFactoryBean` + +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"] +---- + + + + + + + + +---- + +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 the following example, +the `ExampleJob` contains a bean property named `timeout`, and the `JobDetail` +has it applied automatically: + +[source,java,indent=0] +[subs="verbatim"] +---- + package example; + + public class ExampleJob extends QuartzJobBean { + + private int timeout; + + /** + * Setter called after the ExampleJob is instantiated + * with the value from the JobDetailFactoryBean (5) + */ + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException { + // do the actual work + } + } +---- + +All additional properties from the job data map are available to you as well. + +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` (`exampleJob` in the preceding example above). + + +[[scheduling-quartz-method-invoking-job]] +=== Using the `MethodInvokingJobDetailFactoryBean` + +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"] +---- + + + + +---- + +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"] +---- + public class ExampleBusinessObject { + + // properties and collaborators + + public void doIt() { + // do the actual work + } + } +---- + +[source,xml,indent=0,subs="verbatim,quotes"] +---- + +---- + +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 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"] +---- + + + + + +---- + +NOTE: By default, jobs will run in a concurrent fashion. + + +[[scheduling-quartz-cron]] +=== Wiring up Jobs by Using Triggers and `SchedulerFactoryBean` + +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`. + +Triggers need to be scheduled. Spring offers a `SchedulerFactoryBean` that exposes +triggers to be set as properties. `SchedulerFactoryBean` schedules the actual jobs with +those triggers. + +The following listing uses both a `SimpleTriggerFactoryBean` and a `CronTriggerFactoryBean`: + +[source,xml,indent=0] +[subs="verbatim"] +---- + + + + + + + + + + + + + + +---- + +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"] +---- + + + + + + + + +---- + +More properties are available for the `SchedulerFactoryBean`, such as the calendars used by the +job details, properties to customize Quartz with, and a Spring-provided JDBC DataSource. See +the {api-spring-framework}/scheduling/quartz/SchedulerFactoryBean.html[`SchedulerFactoryBean`] +javadoc for more information. + +NOTE: `SchedulerFactoryBean` also recognizes a `quartz.properties` file in the classpath, +based on Quartz property keys, as with regular Quartz configuration. Please note that many +`SchedulerFactoryBean` settings interact with common Quartz settings in the properties file; +it is therefore not recommended to specify values at both levels. For example, do not set +an "org.quartz.jobStore.class" property if you mean to rely on a Spring-provided DataSource, +or specify an `org.springframework.scheduling.quartz.LocalDataSourceJobStore` variant which +is a full-fledged replacement for the standard `org.quartz.impl.jdbcjobstore.JobStoreTX`. +