Modernize the integration section of the refdoc
This commit adds Java and Kotlin tabs to XML code snippets where relevant, and leverages code includes. Closes gh-32600
This commit is contained in:
@@ -518,41 +518,9 @@ disable it by removing only one configuration line rather than all the annotatio
|
||||
your code).
|
||||
|
||||
To enable caching annotations add the annotation `@EnableCaching` to one of your
|
||||
`@Configuration` classes:
|
||||
`@Configuration` classes or use the `cache:annotation-driven` element with XML:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
CacheManager cacheManager() {
|
||||
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||
cacheManager.setCacheSpecification(...);
|
||||
return cacheManager;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Alternatively, for XML configuration you can use the `cache:annotation-driven` element:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:cache="http://www.springframework.org/schema/cache"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||
|
||||
<cache:annotation-driven/>
|
||||
|
||||
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager">
|
||||
<property name="cacheSpecification" value="..."/>
|
||||
</bean>
|
||||
</beans>
|
||||
----
|
||||
include-code::./CacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
|
||||
@@ -13,18 +13,7 @@ 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"]
|
||||
----
|
||||
<!-- simple cache manager -->
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
include-code::./CacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
The preceding snippet uses the `SimpleCacheManager` to create a `CacheManager` for the
|
||||
two nested `ConcurrentMapCache` instances named `default` and `books`. Note that the
|
||||
@@ -52,26 +41,12 @@ of Caffeine.
|
||||
|
||||
The following example configures a `CacheManager` that creates the cache on demand:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="cacheManager"
|
||||
class="org.springframework.cache.caffeine.CaffeineCacheManager"/>
|
||||
----
|
||||
include-code::./CacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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"]
|
||||
----
|
||||
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager">
|
||||
<property name="cacheNames">
|
||||
<set>
|
||||
<value>default</value>
|
||||
<value>books</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
include-code::./CustomCacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
The Caffeine `CacheManager` also supports custom `Caffeine` and `CacheLoader`.
|
||||
See the https://github.com/ben-manes/caffeine/wiki[Caffeine documentation]
|
||||
@@ -97,15 +72,7 @@ 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"]
|
||||
----
|
||||
<bean id="cacheManager"
|
||||
class="org.springframework.cache.jcache.JCacheCacheManager"
|
||||
p:cache-manager-ref="jCacheManager"/>
|
||||
|
||||
<!-- JSR-107 cache manager setup -->
|
||||
<bean id="jCacheManager" .../>
|
||||
----
|
||||
include-code::./CacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
|
||||
[[cache-store-configuration-noop]]
|
||||
@@ -119,18 +86,7 @@ cache declarations (which can prove tedious), you can wire in a simple dummy cac
|
||||
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"]
|
||||
----
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
|
||||
<property name="cacheManagers">
|
||||
<list>
|
||||
<ref bean="jdkCache"/>
|
||||
<ref bean="gemfireCache"/>
|
||||
</list>
|
||||
</property>
|
||||
<property name="fallbackToNoOpCache" value="true"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./CacheConfiguration[tag=snippet,indent=0]
|
||||
|
||||
The `CompositeCacheManager` in the preceding chains multiple `CacheManager` instances and,
|
||||
through the `fallbackToNoOpCache` flag, adds a no-op cache for all the definitions not
|
||||
|
||||
@@ -41,14 +41,7 @@ JavaMail features, such as MIME message support to the `MailSender` interface
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
----
|
||||
include-code::./OrderManager[tag=snippet,indent=0]
|
||||
|
||||
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.
|
||||
@@ -60,70 +53,11 @@ order number needs to be generated and sent to a customer who placed the relevan
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
include-code::./SimpleOrderManager[tag=snippet,indent=0]
|
||||
|
||||
The following example shows the bean definitions for the preceding code:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.mycompany.example"/>
|
||||
</bean>
|
||||
|
||||
<!-- this is a template message that we can pre-load with default state -->
|
||||
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
|
||||
<property name="from" value="customerservice@mycompany.example"/>
|
||||
<property name="subject" value="Your order"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="templateMessage" ref="templateMessage"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./MailConfiguration[tag=snippet,indent=0]
|
||||
|
||||
|
||||
[[mail-usage-mime]]
|
||||
|
||||
@@ -37,23 +37,7 @@ declarations to it.
|
||||
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;
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::./JmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
@@ -67,22 +51,6 @@ container factory. See the javadoc of classes that implement
|
||||
{spring-framework-api}/jms/annotation/JmsListenerConfigurer.html[`JmsListenerConfigurer`]
|
||||
for details and examples.
|
||||
|
||||
If you prefer xref:integration/jms/namespace.adoc[XML configuration], you can use the `<jms:annotation-driven>`
|
||||
element, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<jms:annotation-driven/>
|
||||
|
||||
<bean id="jmsListenerContainerFactory"
|
||||
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destinationResolver" ref="destinationResolver"/>
|
||||
<property name="sessionTransacted" value="true"/>
|
||||
<property name="concurrency" value="3-10"/>
|
||||
</bean>
|
||||
----
|
||||
|
||||
|
||||
[[jms-annotated-programmatic-registration]]
|
||||
== Programmatic Endpoint Registration
|
||||
|
||||
@@ -7,62 +7,13 @@ 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"]
|
||||
----
|
||||
<bean class="org.springframework.jms.listener.endpoint.JmsMessageEndpointManager">
|
||||
<property name="resourceAdapter" ref="resourceAdapter"/>
|
||||
<property name="activationSpecConfig">
|
||||
<bean class="org.springframework.jms.listener.endpoint.JmsActivationSpecConfig">
|
||||
<property name="destinationName" value="myQueue"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="messageListener" ref="myMessageListener"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./JmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
Alternatively, you can set up a `JmsMessageEndpointManager` with a given
|
||||
`ActivationSpec` object. The `ActivationSpec` object may also come from a JNDI lookup
|
||||
(using `<jee:jndi-lookup>`). The following example shows how to do so:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean class="org.springframework.jms.listener.endpoint.JmsMessageEndpointManager">
|
||||
<property name="resourceAdapter" ref="resourceAdapter"/>
|
||||
<property name="activationSpec">
|
||||
<bean class="org.apache.activemq.ra.ActiveMQActivationSpec">
|
||||
<property name="destination" value="myQueue"/>
|
||||
<property name="destinationType" value="jakarta.jms.Queue"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="messageListener" ref="myMessageListener"/>
|
||||
</bean>
|
||||
----
|
||||
|
||||
Using Spring's `ResourceAdapterFactoryBean`, you can configure the target `ResourceAdapter`
|
||||
locally, as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="resourceAdapter" class="org.springframework.jca.support.ResourceAdapterFactoryBean">
|
||||
<property name="resourceAdapter">
|
||||
<bean class="org.apache.activemq.ra.ActiveMQResourceAdapter">
|
||||
<property name="serverUrl" value="tcp://localhost:61616"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="workManager">
|
||||
<bean class="org.springframework.jca.work.SimpleTaskWorkManager"/>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
|
||||
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, you can instead obtain the entire `ResourceAdapter` object from JNDI
|
||||
(by using `<jee:jndi-lookup>`). The Spring-based message listeners can then interact with
|
||||
the server-hosted `ResourceAdapter`, which also use the server's built-in `WorkManager`.
|
||||
include-code::./AlternativeJmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
See the javadoc for {spring-framework-api}/jms/listener/endpoint/JmsMessageEndpointManager.html[`JmsMessageEndpointManager`],
|
||||
{spring-framework-api}/jms/listener/endpoint/JmsActivationSpecConfig.html[`JmsActivationSpecConfig`],
|
||||
|
||||
@@ -31,30 +31,7 @@ on multiple threads, it is important to ensure that your implementation is threa
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::./ExampleListener[tag=snippet,indent=0]
|
||||
|
||||
Once you have implemented your `MessageListener`, it is time to create a message listener
|
||||
container.
|
||||
@@ -62,18 +39,7 @@ 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"]
|
||||
----
|
||||
<!-- this is the Message Driven POJO (MDP) -->
|
||||
<bean id="messageListener" class="jmsexample.ExampleListener"/>
|
||||
|
||||
<!-- and this is the message listener container -->
|
||||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
<property name="messageListener" ref="messageListener"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./JmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
See the Spring javadoc of the various message listener containers (all of which implement
|
||||
{spring-framework-api}/jms/listener/MessageListenerContainer.html[MessageListenerContainer])
|
||||
@@ -123,19 +89,7 @@ messaging support. In a nutshell, it lets you expose almost any class as an MDP
|
||||
|
||||
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);
|
||||
}
|
||||
----
|
||||
include-code::./MessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
Notice that, although the interface extends neither the `MessageListener` nor the
|
||||
`SessionAwareMessageListener` interface, you can still use it as an MDP by using the
|
||||
@@ -145,33 +99,13 @@ 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...
|
||||
}
|
||||
----
|
||||
include-code::./DefaultMessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
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"]
|
||||
----
|
||||
<!-- this is the Message Driven POJO (MDP) -->
|
||||
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
|
||||
<constructor-arg>
|
||||
<bean class="jmsexample.DefaultMessageDelegate"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<!-- and this is the message listener container... -->
|
||||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
<property name="messageListener" ref="messageListener"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./JmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
The next example shows another MDP that can handle only receiving JMS
|
||||
`TextMessage` messages. Notice how the message handling method is actually called
|
||||
@@ -181,38 +115,15 @@ also how the `receive(..)` method is strongly typed to receive and respond only
|
||||
`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);
|
||||
}
|
||||
----
|
||||
include-code::./TextMessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
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...
|
||||
}
|
||||
----
|
||||
include-code::./DefaultTextMessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
The configuration of the attendant `MessageListenerAdapter` would then be as follows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
|
||||
<constructor-arg>
|
||||
<bean class="jmsexample.DefaultTextMessageDelegate"/>
|
||||
</constructor-arg>
|
||||
<property name="defaultListenerMethod" value="receive"/>
|
||||
<!-- we don't want automatic message context extraction -->
|
||||
<property name="messageConverter">
|
||||
<null/>
|
||||
</property>
|
||||
</bean>
|
||||
----
|
||||
include-code::./MessageListenerConfiguration[tag=snippet,indent=0]
|
||||
|
||||
Note that, if the `messageListener` receives a JMS `Message` of a type
|
||||
other than `TextMessage`, an `IllegalStateException` is thrown (and subsequently
|
||||
@@ -220,21 +131,9 @@ swallowed). Another of the capabilities of the `MessageListenerAdapter` class is
|
||||
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 {
|
||||
include-code::./ResponsiveTextMessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
// notice the return type...
|
||||
String receive(TextMessage message);
|
||||
}
|
||||
----
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate {
|
||||
// implementation elided for clarity...
|
||||
}
|
||||
----
|
||||
include-code::./DefaultResponsiveTextMessageDelegate[tag=snippet,indent=0]
|
||||
|
||||
If you use the `DefaultResponsiveTextMessageDelegate` in conjunction with a
|
||||
`MessageListenerAdapter`, any non-null value that is returned from the execution of
|
||||
@@ -264,15 +163,7 @@ has committed but message processing failed to commit.
|
||||
|
||||
Consider the following bean definition:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
<property name="messageListener" ref="messageListener"/>
|
||||
<property name="sessionTransacted" value="true"/>
|
||||
</bean>
|
||||
----
|
||||
include-code::./JmsConfiguration[tag=snippet,indent=0]
|
||||
|
||||
To participate in an externally managed transaction, you need to configure a
|
||||
transaction manager and use a listener container that supports externally managed
|
||||
@@ -288,24 +179,9 @@ semantics, at the expense of XA transaction log overhead).
|
||||
|
||||
The following bean definition creates a transaction manager:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
|
||||
----
|
||||
include-code::./ExternalTxJmsConfiguration[tag=transactionManagerSnippet,indent=0]
|
||||
|
||||
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"]
|
||||
----
|
||||
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destination" ref="destination"/>
|
||||
<property name="messageListener" ref="messageListener"/>
|
||||
<property name="transactionManager" ref="transactionManager"/> <1>
|
||||
</bean>
|
||||
----
|
||||
<1> Our transaction manager.
|
||||
|
||||
|
||||
|
||||
include-code::./ExternalTxJmsConfiguration[tag=jmsContainerSnippet,indent=0]
|
||||
|
||||
@@ -5,63 +5,13 @@ 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",chomp="-packages",chomp="-packages"]
|
||||
----
|
||||
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();
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::./JmxTestBean[tag=snippet,indent=0]
|
||||
|
||||
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"]
|
||||
----
|
||||
<beans>
|
||||
<!-- this bean must not be lazily initialized if the exporting is to happen -->
|
||||
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
|
||||
<property name="beans">
|
||||
<map>
|
||||
<entry key="bean:name=testBean1" value-ref="testBean"/>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
|
||||
<property name="name" value="TEST"/>
|
||||
<property name="age" value="100"/>
|
||||
</bean>
|
||||
</beans>
|
||||
----
|
||||
include-code::./JmxConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
|
||||
@@ -122,25 +122,10 @@ your management interfaces, a convenience subclass of `MBeanExporter` is availab
|
||||
`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:
|
||||
simpler syntax is supported by the `@EnableMBeanExport` `@Configuration` annotation or the `<context:mbean-export/>`
|
||||
element as the following example shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Configuration
|
||||
@EnableMBeanExport
|
||||
public class AppConfig {
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
If you prefer XML-based configuration, the `<context:mbean-export/>` element serves the
|
||||
same purpose and is shown in the following listing:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<context:mbean-export/>
|
||||
----
|
||||
include-code::./JmxConfiguration[tag=snippet,indent=0]
|
||||
|
||||
If necessary, you can provide a reference to a particular MBean `server`, and the
|
||||
`defaultDomain` attribute (a property of `AnnotationMBeanExporter`) accepts an alternate
|
||||
@@ -148,21 +133,7 @@ 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
|
||||
xref:integration/jmx/naming.adoc#jmx-naming-metadata[MetadataNamingStrategy], 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"]
|
||||
----
|
||||
<context:mbean-export server="myMBeanServer" default-domain="myDomain"/>
|
||||
----
|
||||
include-code::./CustomJmxConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
|
||||
@@ -79,38 +79,7 @@ Spring's `TaskExecutor` implementations are commonly used with dependency inject
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::./TaskExecutorExample[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
@@ -118,19 +87,7 @@ 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"]
|
||||
----
|
||||
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||
<property name="corePoolSize" value="5"/>
|
||||
<property name="maxPoolSize" value="10"/>
|
||||
<property name="queueCapacity" value="25"/>
|
||||
</bean>
|
||||
|
||||
<bean id="taskExecutorExample" class="TaskExecutorExample">
|
||||
<constructor-arg ref="taskExecutor"/>
|
||||
</bean>
|
||||
----
|
||||
|
||||
include-code::./TaskExecutorConfiguration[tag=snippet,indent=0]
|
||||
|
||||
|
||||
[[scheduling-task-scheduler]]
|
||||
@@ -269,16 +226,10 @@ execution.
|
||||
=== 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:
|
||||
and `@EnableAsync` to one of your `@Configuration` classes, or `<task:annotation-driven>` element,
|
||||
as the following example shows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
public class AppConfig {
|
||||
}
|
||||
----
|
||||
include-code::./SchedulingConfiguration[tag=snippet,indent=0]
|
||||
|
||||
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
|
||||
@@ -288,16 +239,6 @@ interface, the `AsyncConfigurer` interface, or both. See the
|
||||
and {spring-framework-api}/scheduling/annotation/AsyncConfigurer.html[`AsyncConfigurer`]
|
||||
javadoc for full details.
|
||||
|
||||
If you prefer XML configuration, you can use the `<task:annotation-driven>` element,
|
||||
as the following example shows:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
|
||||
<task:executor id="myExecutor" pool-size="5"/>
|
||||
<task:scheduler id="myScheduler" pool-size="10"/>
|
||||
----
|
||||
|
||||
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`.
|
||||
|
||||
Reference in New Issue
Block a user