(RabbitMQ) Java Client API Guide

简介: 本篇翻译的是RabbitMQ官方文档关于API的内容,原文链接:http://www.rabbitmq.com/api-guide.html。博主对其内容进行大体上的翻译,有些许部分会保留英文,个人觉得这样更加有韵味,如果全部翻译成中文,会存在偏差,文不达意(主要是功力浅薄~~)。

本篇翻译的是RabbitMQ官方文档关于API的内容,原文链接:http://www.rabbitmq.com/api-guide.html。博主对其内容进行大体上的翻译,有些许部分会保留英文,个人觉得这样更加有韵味,如果全部翻译成中文,会存在偏差,文不达意(主要是功力浅薄~~)。文章也对部分内容进行一定的解释,增强对相关知识点的理解。

Overview

RabbitMQ java client uses com.rabbitmq.client as its top-level package, 关键的classes和interface如下:

  • Channel
  • Connection
  • ConnectionFactory
  • Consumer

AMQP协议层面的操作通过Channel接口实现。Connection是用来open Channels的,可以注册event handlers,也可以在结束是close connections. Connection是通过ConnectionFactory来进行初始化操作的,当然也需要配置不同的connection设置,比如vhost或者username等。

Connections and Channels

关键的API如Connection和Channel,分别代表了AMQP-0-9-1的connection和channel。典型的包导入如下:

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;

Connecting to a broker

下面的代码用来在给定的参数(hostname, port number等)下连接一个AMQP broker:

ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
Connection conn = factory.newConnection();

也可以选择使用URI来实现,示例如下:

ConnectionFactory factory = new ConnectionFactory();
factory.setUri("amqp://userName:password@hostName:portNumber/virtualHost");
Connection conn = factory.newConnection();

Connection接口被用来open一个channel:

Channel channel = conn.createChannel();

这样在创建之后,Channel可以用来发送或者接受消息了。
在使用完之后,关闭连接:

channel.close();
conn.close();

显示的关闭channel是一个很好的习惯,但这不是必须的,在基本的connection关闭的时候channel也会自动的关闭。

Using Exchanges and Queues

AMQP的high-level构建模块exchanges和queues是Client端应用所必须的。在使用之前必须先“declared”(声明),确保在使用之前已经存在,如果不存在则创建它,这些操作都包含在declare里。
下面的代码是演示如何declare一个exchange和queue:

channel.exchangeDeclare(exchangeName, "direct", true);
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, exchangeName, routingKey);

上面创建了一个durable, non-autodelete并且绑定类型为direct的exchange以及一个non-durable, exclusive,autodelete的queue(此queue的名称由broker端自动生成)。这里的exchange和queue也都没有设置特殊的arguments。

上面的代码也展示了如果使用routing key将queue和exchange绑定起来。上面声明的queue具备如下特性:排他的(只对当前client同一个Connection可用, 同一个Connection的不同的Channel可共用),并且也会在client连接断开时自动删除。

如果要在client共享一个queue,可以做如下声明:

channel.exchangeDeclare(exchangeName, "direct", true);
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);

这里的queue是durable的,非排他的,non-autodelete, 而且也有一个确定的已知的名称(又Client指定而非broker端自动生成)。

注意:Channel的API方法都是可以重载的,比如exchangeDeclare,queueDeclare根据参数的不同,可以有不同的重载形式,根据自身的需要去进行调用。

Publish messages

如果要发送一个消息可以采用Channel.basicPublish的方式:

byte[] messageBodyBytes = "Hello, world!".getBytes();
channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);

为了更好的控制,你也可以使用mandatory这个属性,或者可以发送一些特定属性的消息:

channel.basicPublish(exchangeName, routingKey, mandatory,
                     MessageProperties.PERSISTENT_TEXT_PLAIN,
                     messageBodyBytes);

这个方法发送了一条消息,这条消息的delivery mode为2,即消息需要被持久化在broker中,同时priority优先级为1,content-type为text/plain。你可以可以自己设定消息的属性:

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .contentType("text/plain")
               .deliveryMode(2)
               .priority(1)
               .userId("bob")
               .build()),
               messageBodyBytes);

你也可以发送一条带有header的消息:

Map<String, Object> headers = new HashMap<String, Object>();
headers.put("latitude",  51.5252949);
headers.put("longitude", -0.0905493);

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .headers(headers)
               .build()),
               messageBodyBytes);

你也可以发送一条带有超时时间expiration的消息:

channel.basicPublish(exchangeName, routingKey,
             new AMQP.BasicProperties.Builder()
               .expiration("60000")
               .build()),
               messageBodyBytes);

以上只是举例,由于篇幅关系,这里就不一一列举所有的可能情形了。

Channel#basicPublish方法在以下两种情形下会被阻塞,具体可以参考http://www.rabbitmq.com/alarms.html

  • When memory use goes above the configured limit.(内存不够)
  • When disk space drops below the configured limit.(磁盘空间不足)

Channles and Concurrency Consideration(Thread Safaty)

Channel实例不能在线程建共享,应用程序应该为每一个线程开辟一个Channel, 而不是在多线程建共享Channel。某些情况下Channel的操作可以并发运行,但是某些情况下并发会导致在网络上错误的帧交叉,同时也会影响publisher confirm, 故多线程共享Channel是非线程安全的。

Receiving messages by subscription

import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;

接受消息一般是通过实现Consumer接口或者继承DefaultConsumer来实现。当调用与Consumer相关的API方法时,不同的订阅采用consumer tags以作彼此的区分,在同一个Channel中的Consumer也需要通过唯一的consumer tags以作区分。。

消费消息demo如下:

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "myConsumerTag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             String routingKey = envelope.getRoutingKey();
             String contentType = properties.getContentType();
             long deliveryTag = envelope.getDeliveryTag();
             // (process the message components here ...)
             channel.basicAck(deliveryTag, false);
         }
     });

注意到上面代码我们显示的设置autoAck=false, 对于Consumer来说这个设置是非常必要的。(译者注:具体可以参考RabbitMQ之消息确认机制(事务+Confirm)中Consumer确认那一章节。)

同时对于Consumer来说重写handleDelivery方法也是十分方便的。更复杂的Consumer会重写(override)更多的方法,比如handleShutdownSignal当channels和connections close的时候会调用,handleConsumeOk在其他callback方法之前调用,返回consumer tags.

Consumer同样可以override handleCancelOk和handleCancel方法,这样在显示的或者隐式的取消的时候调用。

你可以通过Channel.basicCancel方法显示的cancel一个指定的Consumer:

channel.basicCancel(consumerTag);

(译者注:这句代码首先触发handleConsumerOk,之后触发handleDelivery方法,最后触发handleCancelOk方法。)

单个Consumer在Connection上都分配单个的线程来调用这些callback的方法,也就是说Consumer这里安全的调用阻塞式的方法,比如queueDeclare, txCommit, basicCancel或者basicPublish。

每个Channel都有自己的独立的线程。最常用的用法是一个Channel对应一个Consumer, 也就是意味着Consumers彼此间没有任何关联。当然你也可以在一个Channel中维持多个Consumers, 但是要注意一个问题,如果在Channel的一个Consumer一直在运行,那么对于其他Consumer的callbacks而言会被hold up(耽搁)。

Retrieving individual messages

通过Channel.basicGet可以一个一个的获取消息,其返回值是GetResponse(from which the header information(properties) and message body can be extracted)。
示例Demo如下:

boolean autoAck = false;
GetResponse response = channel.basicGet(queueName, autoAck);
if (response == null) {
    // No message retrieved.
} else {
    AMQP.BasicProperties props = response.getProps();
    byte[] body = response.getBody();
    long deliveryTag = response.getEnvelope().getDeliveryTag();
    ...

如果设置autoAck为false,那么你同样需要显示的调用Channel.basicAck来确认消息已经被成功的接受了:

 channel.basicAck(method.deliveryTag, false); // acknowledge receipt of the message

(译者注:有关RabbitMQ的消费端的更多信息可以参考:RabbitMQ之Consumer消费模式(Push & Pull))

Handing unroutable messages

如果一个消息在publish的时候设置了mandatory标记,如果消息没有成功的路由到某个队列的时候,broker端会通过Basic.Return返回回来。

这时候客户端需要实现ReturnListener这个接口,并且调用Channel.setReturnListener。 如果client没有配置相关的return listener那么相应的需要被returned的消息就会被drop掉。

channel.setReturnListener(new ReturnListener() {
    public void handleBasicReturn(int replyCode,
                                  String replyText,
                                  String exchange,
                                  String routingKey,
                                  AMQP.BasicProperties properties,
                                  byte[] body)
    throws IOException {
        ...
    }
});

(译者注:有关mandatory的更多内容可以参考:RabbitMQ之mandatory和immediate。)

Shutdown Protocol

Overview of the AMQP client shutdown

AMQP-0-9-1的connection和channel采用同样的方式来管理网络失败,内部错误以及显示的local shutdown。

AMQP-0-9-1的connection和channel具备如下的生命周期状态(lifecycle states):

  • open: the object is ready to use.
  • closing:当前对象被显示的通知调用shutdown,这样就产生了一个shutdown的请求至lower-layer的对象进行相应的操作,并等待这些shutdown操作的完成。
  • closed:当前对象已经接受到所有的shutdown完成的通知,并且也shutdown了自身。
    这些对象最终成closed的状态,而不管是由于什么原因引起的,或者是一个applicatin request,或者是内部client library的失败,或者是a remote network request, 亦或者是network failure。

AMQP的connecton和channel对象控制(possess)了shutdown-related的方法:addShutdownListener(ShutdownListener listener)和removeShutdownListener(ShutdownListener listener)。当connection和channel转向closed状态时会调用ShutdownListener, 而且如果将一个ShutdownListener注册到一个已经处于closed状态的object(特指connection或者channel的对象)时,会立刻调用ShutdownListener。

  • getCloseReason():可以让你知道the object’s shutdown的原因。
  • isOpen():检测the objects当前的是否处于open状态。
  • close(int closeCode, String closeMessage):显示的通知the object执行shutdown。

示例代码:

import com.rabbitmq.client.ShutdownSignalException;
import com.rabbitmq.client.ShutdownListener;

connection.addShutdownListener(new ShutdownListener() {
    public void shutdownCompleted(ShutdownSignalException cause)
    {
        ...
    }
});

Information about the ircumstances of a shutdown

当触发ShutdownListener的时候,就可以获取到ShutdownSignalException,这个ShutdownSignalException包含了close的原因,这个原因也可以通过getCloseReason()方法获取。

ShutdownSignalException提供了多个方法用来分析shutdown的原因。isHardError()方法可以知道是connection还是channel的error,getReason()方法可以获取cause相关的信息(以AMQP method的形式,com.rabbitmq.client.Method:AMQP.Channel.Close or AMQP.Connection.Close):

public void shutdownCompleted(ShutdownSignalException cause)
{
  if (cause.isHardError())
  {
    Connection conn = (Connection)cause.getReference();
    if (!cause.isInitiatedByApplication())
    {
      Method reason = cause.getReason();
      ...
    }
    ...
  } else {
    Channel ch = (Channel)cause.getReference();
    ...
  }
}

Atomicity and use of the isOpen() method

我们并不推荐在生产环境的代码上使用channel或者connection的isOpen()方法,这个isOpen()方法的返回值依赖于shutdown cause的存在,有可能会产生竞争。
(译者添加:关于isOpen依赖于shutdown cause, isOpen的实现代码如下:)

    public boolean isOpen() {
        synchronized(this.monitor) {
            return this.shutdownCause == null;
        }
    }

错误的使用方式如下:

public void brokenMethod(Channel channel)
{
    if (channel.isOpen())
    {
        // The following code depends on the channel being in open state.
        // However there is a possibility of the change in the channel state
        // between isOpen() and basicQos(1) call
        ...
        channel.basicQos(1);
    }
}

正确的使用方式:

public void validMethod(Channel channel)
{
    try {
        ...
        channel.basicQos(1);
    } catch (ShutdownSignalException sse) {
        // possibly check if channel was closed
        // by the time we started action and reasons for
        // closing it
        ...
    } catch (IOException ioe) {
        // check why connection was closed
        ...
    }
}

Advanced Connection options

Consumer thread pool

默认情况下客户端会自动分配一个ExecutorService给Consumer线程,同样你也可以使用自定义的线程池,比如:

ExecutorService es = Executors.newFixedThreadPool(20);
Connection conn = factory.newConnection(es);

当connection关闭的时候,默认的ExecutorService会被shutdown,但是如果是自定义的ExecutorService将不会被自动的shutdown,所以Clients程序需要在最终关闭的时候手动的去执行shutdown(),否则将会阻止JVM的正常关闭。

同一个executor service可以被多个connections共用。除非有明显的证据证明默认的ExecutorService不能满足当前Consumer callbacks的需要,否则不建议使用自定义的ExecutorService.

Using Lists of Hosts

可以通过使用Address来执行newConnection(). com.rabbitmq.client.Address的使用是比较方便的,例如:

Address[] addrArr = new Address[]{ new Address(hostname1, portnumber1)
                                 , new Address(hostname2, portnumber2)};
Connection conn = factory.newConnection(addrArr);

如果hostname1:portnumber1成功了连接,而hostname2:portnumber2连接失败了,connection照样会成功returned, 也不会跑出IOException。这个和你重复设置host,port然后调用factory.newConnection()直到有一组成功为止一个效果。

同样可以指定自定义的ExecutorService, 比如:factory.newConnection(es, addrArr)。

If you want moew control over the host to connect to, see the support for service discovery.

Service discovery with the AddressResolver interface

在版本3.6.6开始,可以通过AddressResolver接口的实现来创建connection:

Connection conn = factory.newConnection(addressResolver);

AddressResolver接口如下:

public interface AddressResolver {
  List<Address> getAddresses() throws IOException;
}

使用AddressResolver可以更好的实现custom service discovery逻辑,和“automatic recovery”组合使用,客户端可以自动的和broker nodes连接.AddressResolver也可以有效的配合负载均衡策略。

AddressResolver有两个实现:DnsRecordIpAddressResolver和DnsSrvRecordAddressResolver.(博主没用过AddressResolver,这里就不多做解释了)

Heartbeat Timeout

有关Heartbeat的内容请参考Heatbeats guide。(原文就是这么说的。)

Custom Thread Factories

略。和Google App Engine有关。

Support for Java non-blocking IO

4.0版本开始客户端引入了java的NIO,这里引入NIO的目的不是为了比BIO的更快,而是是的更加容易的控制资源。

对于默认的BIO模式,每个connection都需要一个独立的线程来进行网络通讯。但在NIO模式下,你可以控制网络通讯读写线程的数量。

如果你的java程序需要许多的connections(几十个或者几百个),那么使用NIO模式是一个很好的选择。相比BIO而言,你所使用的线程数很少,通过设置合理的线程数,你可以不必担心性能的损耗,尤其是在connections不怎么busy的时候。

NIO必须被显示的设置:

ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.useNio();

你也可以设置NIO的参数:

connectionFactory.setNioParams(new NioParams().setNbIoThreads(4));

NIO模式下使用合理的默认值,同时你也可以根据自身的负载情况来进行合理的变换。

Automatic Recovery From Network Failures

Connection Recovery

客户端和broker之间的网络通讯可能会失败。RabbitMQ java client支持connections和拓扑topology(指queues, exchanges, bindings and consumers)的自动回复。自动恢复过程有如下几个步骤:

  • Reconnect
  • Restore connection listeners
  • Re-open channels
  • Restore channel listeners
  • Restore channel basic.qos setting, publisher confirms and transaction settings

topology的恢复包括如下行为,performed for every channel:

  • Re-declare exchange (exception for predefined ones)
  • Re-declare queues
  • Recover all bindings
  • Recover all consumers

在版本4.0.0开始,自动回复默认是开启的。你也通过factory.setAutomaticRecoveryEnabled(boolean)可以手动的设置automatic onnection recovery.

ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
factory.setAutomaticRecoveryEnabled(true);
// connection that will recover automatically
Connection conn = factory.newConnection();

如果由于某些异常(比如RabbitMQ节点始终连接不上)而导致的恢复失败。那么会在某个特定的时间间隔内重试,默认此间隔为5s,当然此值可配:

ConnectionFactory factory = new ConnectionFactory();
// attempt recovery every 10 seconds
factory.setNetworkRecoveryInterval(10000);

Recovery Listeners

It is possible to register one or more recovery listeners on recoverable connections and channels. 当connection recovery启用的时候,通过调用ConnectionFactory#newConnection和Connection#createChannel返回的connections实现com.rabbitmq.client.Recoverable. 这里提供了两个方法:addRecoveryListener和removerRecoveryListener.

/**
 * Provides a way to register (network, AMQP 0-9-1) connection recovery
 * callbacks.
 *
 * When connection recovery is enabled via {@link ConnectionFactory},
 * {@link ConnectionFactory#newConnection()} and {@link Connection#createChannel()}
 * return {@link Recoverable} connections and channels.
 *
 * @see com.rabbitmq.client.impl.recovery.AutorecoveringConnection
 * @see com.rabbitmq.client.impl.recovery.AutorecoveringChannel
 */
public interface Recoverable {
    /**
     * Registers a connection recovery callback.
     *
     * @param listener Callback function
     */
    void addRecoveryListener(RecoveryListener listener);
    void removeRecoveryListener(RecoveryListener listener);
}

当然你必须将connections和channels强制转换为Recoverable的才能使用这些方法。

Effects on Publishing

消息通过Channel,basicPublish发布,如果connection down了那么消息就会丢失。客户端不会在connection恢复之后重新delivery这些消息。为了确保消息的可靠性,可以参考Publisher Confims.(或者可以参考博主的博文:RabbitMQ之消息确认机制(事务+Confirm))。

Topology Recovery

Topology recovery涉及到exchanges, queues, bindings and consumer.当automatic recovery可用时topology recovery默认也可用。当然topology也可显示的设置为disabled:

ConnectionFactory factory = new ConnectionFactory();

Connection conn = factory.newConnection();
// enable automatic recovery (e.g. Java client prior 4.0.0)
factory.setAutomaticRecoveryEnabled(true);
// disable topology recovery
factory.setTopologyRecoveryEnabled(false);

Manual Acknowledgements and Automatic Recovery

当autoAck设置为false的时候,在消息delivery和ack的时候有可能会由于网络原因故障,在connection recovery之后,RabbitMQ会将所有的channels的delivery tags进行重置。这就意味着basic.ack, basic,nack以及basic.reject带有old delivery tags的将会引起channel exception。为了解决这个为题,RabbitMQ java client会记录和更新相应的delivery tags来确保在恢复期间保持单调递增。带有过时的delivery tags的ack将不会被发送。采用manual ack和automatic recovery的应用必须具备处理redeliveries的能力。

Unhandled Exceptions

在connection, channel, recovery, consumer生命周期内涉及的未被处理的异常可以委托给exception handler. Exception handler实现了ExceptionHandler这个接口,默认情况下使用的是DefaultExceptionHandler, 只是在标准输出流中打印一些exception的细节。

你可以使用ConnectionFactory#setExceptionHandler来override这个handler,这个handler可以被ConnectionFactory创建的所有的Connections所使用:

ConnectionFactory factory = new ConnectionFactory();
factory.setExceptionHandler(customHandler);

Metrics and monitoring

RabbitMQ Java Client on Google App Engine

Cavets and Limitations

The RPC Pattern

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
3天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
6天前
|
存储 Java 关系型数据库
掌握Java 8 Stream API的艺术:详解流式编程(一)
掌握Java 8 Stream API的艺术:详解流式编程
34 1
|
15天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
25天前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
90 3
|
26天前
|
分布式计算 Java 程序员
Java 8新特性之Lambda表达式与Stream API
本文将详细介绍Java 8中的两个重要新特性:Lambda表达式和Stream API。Lambda表达式是Java 8中引入的一种简洁、匿名的函数表示方法,它允许我们将函数作为参数传递给其他方法。而Stream API则是一种新的数据处理方式,它允许我们以声明式的方式处理数据,从而提高代码的可读性和可维护性。通过本文的学习,你将能够掌握Lambda表达式和Stream API的基本用法,以及如何在项目中应用这两个新特性。
30 10
|
26天前
|
Java API 数据处理
Java 8新特性之Lambda表达式与Stream API
本文将介绍Java 8中的两个重要特性:Lambda表达式和Stream API。Lambda表达式是一种新的语法结构,允许我们将函数作为参数传递给方法。而Stream API则是一种处理数据的新方式,它允许我们对数据进行更简洁、更高效的操作。通过学习这两个特性,我们可以编写出更简洁、更易读的Java代码。
|
27天前
|
Java API Maven
email api java编辑方法?一文教你学会配置步骤
在Java开发中,Email API是简化邮件功能的关键工具。本文指导如何配置和使用Email API Java:首先,在项目中添加javax.mail-api和javax.mail依赖;接着,配置SMTP服务器和端口;然后,创建邮件,设定收件人、发件人、主题和正文;最后,使用Transport.send()发送邮件。借助Email API Java,可为应用添加高效邮件功能。
|
9天前
|
缓存 前端开发 API
API接口封装系列
API(Application Programming Interface)接口封装是将系统内部的功能封装成可复用的程序接口并向外部提供,以便其他系统调用和使用这些功能,通过这种方式实现系统之间的通信和协作。下面将介绍API接口封装的一些关键步骤和注意事项。
|
16天前
|
监控 前端开发 JavaScript
实战篇:商品API接口在跨平台销售中的有效运用与案例解析
随着电子商务的蓬勃发展,企业为了扩大市场覆盖面,经常需要在多个在线平台上展示和销售产品。然而,手工管理多个平台的库存、价格、商品描述等信息既耗时又容易出错。商品API接口在这一背景下显得尤为重要,它能够帮助企业在不同的销售平台之间实现商品信息的高效同步和管理。本文将通过具体的淘宝API接口使用案例,展示如何在跨平台销售中有效利用商品API接口,以及如何通过代码实现数据的统一管理。
|
28天前
|
安全 算法 API
产品经理必备知识——API接口
前言 在古代,我们的传输信息的方式有很多,比如写信、飞鸽传书,以及在战争中使用的烽烟,才有了著名的烽火戏诸侯,但这些方式传输信息的效率终究还是无法满足高速发展的社会需要。如今万物互联的时代,我通过一部手机就可以实现衣食住行的方方面面,比如:在家购物、远程控制家电、自动驾驶等等,背后都离不开我们今天要聊的API接口。