Come usare l'API JMS (Java Message Service) con il bus di servizio e AMQP 1.0How to use the Java Message Service (JMS) API with Service Bus and AMQP 1.0

AMQP (Advanced Message Queuing Protocol) 1.0 è un protocollo di messaggistica wire-level efficiente e affidabile che può essere utilizzato per creare potenti applicazioni di messaggistica multipiattaforma.The Advanced Message Queuing Protocol (AMQP) 1.0 is an efficient, reliable, wire-level messaging protocol that you can use to build robust, cross-platform messaging applications.

Grazie al supporto per AMQP 1.0 nel bus di servizio, è ora possibile utilizzare le funzionalità di accodamento e di messaggistica negoziata di pubblicazione/sottoscrizione da numerose piattaforme, tramite un efficiente protocollo binario.Support for AMQP 1.0 in Service Bus means that you can use the queuing and publish/subscribe brokered messaging features from a range of platforms using an efficient binary protocol. Inoltre, è possibile creare applicazioni costituite da componenti creati con un insieme di linguaggi, framework e sistemi operativi.Furthermore, you can build applications comprised of components built using a mix of languages, frameworks, and operating systems.

Questo articolo illustra come usare le funzionalità di messaggistica del bus di servizio, ad esempio code e pubblicazione/sottoscrizione di argomenti, da applicazioni Java usando l'API standard JMS più richiesta (Java Message Service).This article explains how to use Service Bus messaging features (queues and publish/subscribe topics) from Java applications using the popular Java Message Service (JMS) API standard. È disponibile un articolo complementare che illustra come eseguire le stesse procedure usando l'API . NET del bus di servizio.There is a companion article that explains how to do the same using the Service Bus .NET API. È possibile consultare queste due guide per acquisire informazioni sulla messaggistica multipiattaforma con AMQP 1.0.You can use these two guides together to learn about cross-platform messaging using AMQP 1.0.

Introduzione al bus di servizioGet started with Service Bus

In questa guida si presuppone di avere già uno spazio dei nomi del bus di servizio contenente una coda denominata coda1.This guide assumes that you already have a Service Bus namespace containing a queue named queue1. In caso contrario, è necessario creare lo spazio dei nomi e la coda tramite il portale di Azure.If you do not, then you can create the namespace and queue using the Azure portal. Per altre informazioni su come creare spazi dei nomi e code del bus di servizio, vedere Introduzione alle code del bus di servizio.For more information about how to create Service Bus namespaces and queues, see Get started with Service Bus queues.

Nota

Le code e gli argomenti partizionati supportano anche AMQP.Partitioned queues and topics also support AMQP. Per altre informazioni, vedere le entità di messaggistica partizionate e Supporto di AMQP 1.0 per code e argomenti partizionati del bus di servizio.For more information, see Partitioned messaging entities and AMQP 1.0 support for Service Bus partitioned queues and topics.

Download della libreria client JMS basata su AMQP 1.0Downloading the AMQP 1.0 JMS client library

Per informazioni su dove scaricare l'ultima versione della libreria client JMS basata su AMQP 1.0 di Apache Qpid, visitare la pagina https://qpid.apache.org/download.html.For information about where to download the latest version of the Apache Qpid JMS AMQP 1.0 client library, visit https://qpid.apache.org/download.html.

È necessario aggiungere i seguenti quattro file JAR dall'archivio di distribuzione AMQP 1.0 di Apache Qpid al CLASSPATH Java durante la compilazione e l'esecuzione di applicazioni JMS con il bus di servizio:You must add the following four JAR files from the Apache Qpid JMS AMQP 1.0 distribution archive to the Java CLASSPATH when building and running JMS applications with Service Bus:

  • geronimo-jms_1.1_spec-1.0.jargeronimo-jms_1.1_spec-1.0.jar
  • qpid-amqp-1-0-client-[version].jarqpid-amqp-1-0-client-[version].jar
  • qpid-amqp-1-0-client-jms-[version].jarqpid-amqp-1-0-client-jms-[version].jar
  • qpid-amqp-1-0-common-[version].jarqpid-amqp-1-0-common-[version].jar

Compilazione di applicazioni JavaCoding Java applications

Java Naming and Directory Interface (JNDI)Java Naming and Directory Interface (JNDI)

JMS usa l'interfaccia JNDI (Java Naming and Directory Interface) per creare una separazione tra i nomi logici e i nomi fisici.JMS uses the Java Naming and Directory Interface (JNDI) to create a separation between logical names and physical names. Con JNDI vengono risolti due tipi di oggetti JMS: ConnectionFactory e Destination.Two types of JMS objects are resolved using JNDI: ConnectionFactory and Destination. JNDI utilizza un modello di provider in cui è possibile inserire diversi servizi directory per gestire le attività di risoluzione dei nomi.JNDI uses a provider model into which you can plug different directory services to handle name resolution duties. La libreria JMS basata su AMQP 1.0 di Apache Qpid viene fornita con un semplice provider JNDI, basato su un file delle proprietà, che viene configurato mediante un file di testo:The Apache Qpid JMS AMQP 1.0 library comes with a simple properties file-based JNDI Provider that is configured using a properties file of the following format:

# servicebus.properties - sample JNDI configuration

# Register a ConnectionFactory in JNDI using the form:
# connectionfactory.[jndi_name] = [ConnectionURL]
connectionfactory.SBCF = amqps://[SASPolicyName]:[SASPolicyKey]@[namespace].servicebus.windows.net

# Register some queues in JNDI using the form
# queue.[jndi_name] = [physical_name]
# topic.[jndi_name] = [physical_name]
queue.QUEUE = queue1

Configurare ConnectionFactoryConfigure the ConnectionFactory

La voce usata per definire un oggetto ConnectionFactory nel provider JNDI basato sul file delle proprietà Qpid è nel formato seguente:The entry used to define a ConnectionFactory in the Qpid properties file JNDI provider is of the following format:

connectionfactory.[jndi_name] = [ConnectionURL]

Dove [jndi_name] e [ConnectionURL] hanno i significati seguenti:Where [jndi_name] and [ConnectionURL] have the following meanings:

  • [jndi_name]: nome logico dell'oggetto ConnectionFactory.[jndi_name]: The logical name of the ConnectionFactory. Tale nome viene risolto nell'applicazione Java mediante l'utilizzo del metodo JNDI IntialContext.lookup().This is the name that will be resolved in the Java application using the JNDI IntialContext.lookup() method.
  • [ConnectionURL]: URL che comunica alla libreria JMS le informazioni necessarie per il broker AMQP.[ConnectionURL]: A URL that provides the JMS library with the information required to the AMQP broker.

Il formato di ConnectionURL è il seguente:The format of the ConnectionURL is as follows:

amqps://[SASPolicyName]:[SASPolicyKey]@[namespace].servicebus.windows.net

Dove [namespace], [SASPolicyName] e [SASPolicyKey] hanno i significati seguenti:Where [namespace], [SASPolicyName] and [SASPolicyKey] have the following meanings:

  • [namespace]: spazio dei nomi del bus di servizio.[namespace]: The Service Bus namespace.
  • [SASPolicyName]: nome del criterio della firma di accesso condiviso relativa alla coda.[SASPolicyName]: The Queue Shared Access Signature policy name.
  • [SASPolicyKey]: chiave del criterio della firma di accesso condiviso relativa alla coda.[SASPolicyKey]: The Queue Shared Access Signature policy key.

Nota

è necessario applicare manualmente la codifica URL alla password.You must URL-encode the password manually. Sul sito http://www.w3schools.com/tags/ref_urlencode.asp è disponibile un'utilità per codificare facilmente l'URL.A useful URL-encoding utility is available at http://www.w3schools.com/tags/ref_urlencode.asp.

Configurare le destinazioniConfigure destinations

La voce usata per definire una destinazione nel provider JNDI basato sul file delle proprietà Qpid è nel formato seguente:The entry used to define a destination in the Qpid properties file JNDI provider is of the following format:

queue.[jndi_name] = [physical_name]

oppureor

topic.[jndi_name] = [physical_name]

Dove [jndi_name] e [physical_name] hanno i significati seguenti:Where [jndi_name] and [physical_name] have the following meanings:

  • [jndi_name]: nome logico della destinazione.[jndi_name]: The logical name of the destination. Tale nome viene risolto nell'applicazione Java mediante l'utilizzo del metodo JNDI IntialContext.lookup().This is the name that will be resolved in the Java application using the JNDI IntialContext.lookup() method.
  • [physical_name]: nome dell'entità del bus di servizio a cui l'applicazione invia messaggi o da cui l'applicazione riceve messaggi.[physical_name]: The name of the Service Bus entity to which the application sends or receives messages.

Nota

In caso di ricezione da una sottoscrizione a un argomento del bus di servizio, il nome fisico specificato in JNDI deve essere il nome dell'argomento.When receiving from a Service Bus topic subscription, the physical name specified in JNDI should be the name of the topic. Il nome della sottoscrizione viene fornito al momento della creazione della sottoscrizione durevole nel codice dell'applicazione JMS.The subscription name is provided when the durable subscription is created in the JMS application code. La guida per sviluppatori di AMQP 1.0 per il bus di servizio include istruzioni dettagliate sull'uso di argomenti del bus di servizio di JMS.The Service Bus AMQP 1.0 Developer's Guide provides more details on working with Service Bus topics from JMS.

Scrivere l'applicazione JMSWrite the JMS application

Non esistono API speciali oppure opzioni obbligatorie quando si utilizza JMS con il bus di servizio.There are no special APIs or options required when using JMS with Service Bus. Tuttavia, esistono alcune limitazioni che verranno illustrate più avanti.However, there are a few restrictions that will be covered later. Come per qualsiasi applicazione JMS, la prima operazione da eseguire è la configurazione dell'ambiente JNDI, in modo da poter risolvere gli oggetti di tipo ConnectionFactory e le destinazioni.As with any JMS application, the first thing required is configuration of the JNDI environment, to be able to resolve a ConnectionFactory and destinations.

Configurare il contesto JNDI inizialeConfigure the JNDI InitialContext

La configurazione dell'ambiente JNDI viene eseguita passando una tabella hash di informazioni di configurazione al costruttore della classe javax.naming.InitialContext.The JNDI environment is configured by passing a hashtable of configuration information into the constructor of the javax.naming.InitialContext class. I due elementi necessari nella tabella hash sono il nome della classe della factory del contesto iniziale e l'URL del provider.The two required elements in the hashtable are the class name of the Initial Context Factory and the Provider URL. Nel codice seguente viene illustrato come configurare l'ambiente JNDI per usare il provider JNDI basato sul file delle proprietà Qpid con un file delle proprietà denominato servicebus.properties.The following code shows how to configure the JNDI environment to use the Qpid properties file based JNDI Provider with a properties file named servicebus.properties.

Hashtable<String, String> env = new Hashtable<String, String>(); 
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory"); 
env.put(Context.PROVIDER_URL, "servicebus.properties"); 
InitialContext context = new InitialContext(env);

Semplice applicazione JMS che usa la coda del bus di servizioA simple JMS application using a Service Bus queue

L'applicazione di esempio seguente consente di inviare e ricevere messaggi di testo JMS verso e da una coda del bus di servizio con il nome JNDI logico QUEUE.The following example program sends JMS TextMessages to a Service Bus queue with the JNDI logical name of QUEUE, and receives the messages back.

// SimpleSenderReceiver.java

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Hashtable;
import java.util.Random;

public class SimpleSenderReceiver implements MessageListener {
    private static boolean runReceiver = true;
    private Connection connection;
    private Session sendSession;
    private Session receiveSession;
    private MessageProducer sender;
    private MessageConsumer receiver;
    private static Random randomGenerator = new Random();

    public SimpleSenderReceiver() throws Exception {
        // Configure JNDI environment
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
                   "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
        env.put(Context.PROVIDER_URL, "servicebus.properties");
        Context context = new InitialContext(env);

        // Look up ConnectionFactory and Queue
        ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
        Destination queue = (Destination) context.lookup("QUEUE");

        // Create Connection
        connection = cf.createConnection();

        // Create sender-side Session and MessageProducer
        sendSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        sender = sendSession.createProducer(queue);

        if (runReceiver) {
            // Create receiver-side Session, MessageConsumer,and MessageListener
            receiveSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
            receiver = receiveSession.createConsumer(queue);
            receiver.setMessageListener(this);
            connection.start();
        }
    }

    public static void main(String[] args) {
        try {

            if ((args.length > 0) && args[0].equalsIgnoreCase("sendonly")) {
                runReceiver = false;
            }

            SimpleSenderReceiver simpleSenderReceiver = new SimpleSenderReceiver();
            System.out.println("Press [enter] to send a message. Type 'exit' + [enter] to quit.");
            BufferedReader commandLine = new java.io.BufferedReader(new InputStreamReader(System.in));

            while (true) {
                String s = commandLine.readLine();
                if (s.equalsIgnoreCase("exit")) {
                    simpleSenderReceiver.close();
                    System.exit(0);
                } else {
                    simpleSenderReceiver.sendMessage();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendMessage() throws JMSException {
        TextMessage message = sendSession.createTextMessage();
        message.setText("Test AMQP message from JMS");
        long randomMessageID = randomGenerator.nextLong() >>>1;
        message.setJMSMessageID("ID:" + randomMessageID);
        sender.send(message);
        System.out.println("Sent message with JMSMessageID = " + message.getJMSMessageID());
    }

    public void close() throws JMSException {
        connection.close();
    }

    public void onMessage(Message message) {
        try {
            System.out.println("Received message with JMSMessageID = " + message.getJMSMessageID());
            message.acknowledge();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}    

Eseguire l'applicazioneRun the application

L'esecuzione dell'applicazione produce un output nel formato seguente:Running the application produces output of the form:

> java SimpleSenderReceiver
Press [enter] to send a message. Type 'exit' + [enter] to quit.

Sent message with JMSMessageID = ID:2867600614942270318
Received message with JMSMessageID = ID:2867600614942270318

Sent message with JMSMessageID = ID:7578408152750301483
Received message with JMSMessageID = ID:7578408152750301483

Sent message with JMSMessageID = ID:956102171969368961
Received message with JMSMessageID = ID:956102171969368961
exit

Messaggistica multipiattaforma tra JMS e .NETCross-platform messaging between JMS and .NET

In questa guida è stato illustrato come inviare e ricevere messaggi verso e dal bus di servizio utilizzando JMS.This guide showed how to send and receive messages to and from Service Bus using JMS. Tuttavia, uno dei principali vantaggi di AMQP 1.0 è che consente di creare applicazioni da componenti scritti in linguaggi diversi, con i messaggi scambiati in modo affidabile e con la massima fedeltà.However, one of the key benefits of AMQP 1.0 is that it enables applications to be built from components written in different languages, with messages exchanged reliably and at full fidelity.

Con l'uso dell'applicazione JMS di esempio descritta in precedenza e un'applicazione .NET simile presa dall'articolo complementare Come usare AMQP 1.0 con l'API .NET del bus di servizio, è possibile scambiare messaggi tra .NET e Java.Using the sample JMS application described above and a similar .NET application taken from a companion article, Using Service Bus from .NET with AMQP 1.0, you can exchange messages between .NET and Java. Leggere questo articolo per altre informazioni sulla messaggistica multipiattaforma che usa il bus di servizio e AMQP 1.0.Read this article for more information about the details of cross-platform messaging using Service Bus and AMQP 1.0.

Da JMS a .NETJMS to .NET

Per verificare la messaggistica da JMS a .NET, eseguire la procedura seguente:To demonstrate JMS to .NET messaging:

  • Avviare l'applicazione di esempio .NET senza argomenti della riga di comando.Start the .NET sample application without any command-line arguments.
  • Avviare l'applicazione di esempio Java con l'argomento della riga di comando "sendonly".Start the Java sample application with the "sendonly" command-line argument. In questa modalità l'applicazione non riceverà messaggi dalla coda, ma potrà solo inviarne.In this mode, the application will not receive messages from the queue, it will only send.
  • Premere alcune volte INVIO nella console dell'applicazione Java per inviare i messaggi.Press Enter a few times in the Java application console, which will cause messages to be sent.
  • Questi messaggi vengono ricevuti dall'applicazione .NET.These messages are received by the .NET application.

Output dell'applicazione JMSOutput from JMS application

> java SimpleSenderReceiver sendonly
Press [enter] to send a message. Type 'exit' + [enter] to quit.
Sent message with JMSMessageID = ID:4364096528752411591
Sent message with JMSMessageID = ID:459252991689389983
Sent message with JMSMessageID = ID:1565011046230456854
exit

Output dell'applicazione .NETOutput from .NET application

> SimpleSenderReceiver.exe    
Press [enter] to send a message. Type 'exit' + [enter] to quit.
Received message with MessageID = 4364096528752411591
Received message with MessageID = 459252991689389983
Received message with MessageID = 1565011046230456854
exit

Da .NET a JMS.NET to JMS

Per verificare la messaggistica da .NET a JMS, eseguire la procedura seguente:To demonstrate .NET to JMS messaging:

  • Avviare l'applicazione di esempio .NET con l'argomento "sendonly" della riga di comando.Start the .NET sample application with the "sendonly" command-line argument. In questa modalità l'applicazione non riceverà messaggi dalla coda, ma potrà solo inviarne.In this mode, the application will not receive messages from the queue, it will only send.
  • Avviare l'applicazione di esempio Java senza argomenti della riga di comando.Start the Java sample application without any command-line arguments.
  • Premere alcune volte INVIO nella console dell'applicazione .NET per inviare i messaggi.Press Enter a few times in the .NET application console, which will cause messages to be sent.
  • Questi messaggi vengono ricevuti dall'applicazione Java.These messages are received by the Java application.

Output dell'applicazione .NETOutput from .NET application

> SimpleSenderReceiver.exe sendonly
Press [enter] to send a message. Type 'exit' + [enter] to quit.
Sent message with MessageID = d64e681a310a48a1ae0ce7b017bf1cf3    
Sent message with MessageID = 98a39664995b4f74b32e2a0ecccc46bb
Sent message with MessageID = acbca67f03c346de9b7893026f97ddeb
exit

Output dell'applicazione JMSOutput from JMS application

> java SimpleSenderReceiver    
Press [enter] to send a message. Type 'exit' + [enter] to quit.
Received message with JMSMessageID = ID:d64e681a310a48a1ae0ce7b017bf1cf3
Received message with JMSMessageID = ID:98a39664995b4f74b32e2a0ecccc46bb
Received message with JMSMessageID = ID:acbca67f03c346de9b7893026f97ddeb
exit

Funzionalità non supportate e restrizioniUnsupported features and restrictions

Quando si utilizza JMS su AMQP 1.0 con il bus di servizio esistono le seguenti restrizioni:The following restrictions exist when using JMS over AMQP 1.0 with Service Bus, namely:

  • È consentito solo un oggetto MessageProducer o MessageConsumer per sessione.Only one MessageProducer or MessageConsumer is allowed per Session. Se si vuole creare più oggetti MessageProducers o MessageConsumers in un'applicazione, creare una sessione dedicata per ognuno di essi.If you need to create multiple MessageProducers or MessageConsumers in an application, create a dedicated Session for each of them.
  • Le sottoscrizioni a un argomento volatile non sono attualmente supportate.Volatile topic subscriptions are not currently supported.
  • Gli oggettiMessageSelectors non sono attualmente supportati.MessageSelectors are not currently supported.
  • Le destinazioni temporanee, ad esempio TemporaryQueue e TemporaryTopic, non sono attualmente supportate, così come le API QueueRequestor e TopicRequestor da cui vengono usate.Temporary destinations; for example, TemporaryQueue, TemporaryTopic are not currently supported, along with the QueueRequestor and TopicRequestor APIs that use them.
  • Le sessioni transazionali non sono supportate e le transazioni distribuite non sono supportate.Transacted sessions and distributed transactions are not supported.

RiepilogoSummary

Questa guida dettagliata ha illustrato come accedere alle funzionalità di messaggistica negoziata (code e pubblicazione/sottoscrizione di argomenti) del bus di servizio da Java usando la diffusa API JMS e AMQP 1.0.This how-to guide showed how to use Service Bus brokered messaging features (queues and publish/subscribe topics) from Java using the popular JMS API and AMQP 1.0.

È anche possibile utilizzare AMQP 1.0 per il bus di servizio da altri linguaggi, tra cui .NET, C, Python e PHP.You can also use Service Bus AMQP 1.0 from other languages, including .NET, C, Python, and PHP. I componenti creati con questi linguaggi possono scambiare messaggi in modo affidabile e con la massima fedeltà grazie al supporto per AMQP 1.0 nel bus di servizio.Components built using these different languages can exchange messages reliably and at full fidelity using the AMQP 1.0 support in Service Bus.

Passaggi successiviNext steps