阿里P8重磅總結(jié):看完別說不會了哦,SpringBoot「完結(jié)篇」

一、 緩存

1)JSR107

Java Caching定義了5個核心接口,分別是

  • CachingProvider

定義了創(chuàng)建、配置、獲取、管理和控制多個CacheManager。一個應用可以在運行期訪問多個CachingProvider。

  • CacheManager

定義了創(chuàng)建、配置、獲取、管理和控制多個唯一命名的Cache,這些Cache存在于CacheManager的上下文中。一個CacheManager僅被一個CachingProvider所擁有。

  • Cache

是一個類似Map的數(shù)據(jù)結(jié)構(gòu)并臨時存儲以Key為索引的值。一個Cache僅被一個CacheManager所擁有。

  • Entry

是一個存儲在Cache中的key-value對。

  • Expiry

每一個存儲在Cache中的條目有一個定義的有效期。一旦超過這個時間,條目為過期的狀態(tài)。一旦過期,條目將不可訪問、更新和刪除。緩存有效期可以通過ExpiryPolicy設置。

image.png

2)Spring緩存抽象

Spring從3.1開始定義了
org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統(tǒng)一不同的緩存技術(shù),并支持使用JCache(JSR-107)注解簡化我們開發(fā)。

  • Cache接口為緩存的組件規(guī)范定義,包含緩存的各種操作集合
  • Cache接口下Spring提供了各種xxxCache的實現(xiàn);如RedisCache,EhCacheCache ,ConcurrentMapCache等
  • 每次調(diào)用需要緩存功能的方法時,Spring會檢查指定參數(shù)的指定的目標方法是否已經(jīng)被調(diào)用過,如果有就直接從緩存中獲取方法調(diào)用后的結(jié)果,如果沒有就調(diào)用方法并緩存結(jié)果后返回給用戶。下次調(diào)用直接從緩存中獲取。
  • 使用Spring緩存抽象時我們需要關(guān)注以下兩點:
  1. 確定方法需要被緩存以及他們的緩存策略
  2. 從緩存中讀取之前緩存存儲的數(shù)據(jù)
image.png

3)幾個重要緩存注解

image.png
image.png
image.png

4)緩存使用

  • 引入spring-boot-starter-cache模塊
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
復制代碼
  • 利用@EnableCaching開啟緩存
@MapperScan("cbuc.life.cache.mapper")
@SpringBootApplication
@EnableCaching
public class Springboot01CacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot01CacheApplication.class, args);
    }
}
復制代碼
  • 注解使用
  1. @Cacheable
  2. @CacheEvict
  3. @CachePut

將數(shù)據(jù)保存在ConcurrentMap<Object, Object>中
開發(fā)中使用緩存中間件:redis、memcached、ehcache

5)幾大屬性

  1. cacheNames/value: 指定緩存組件的名字,將方法的返回結(jié)果放在哪個緩存中,是數(shù)組的方式,可以指定多個緩存
  2. key: 緩存數(shù)據(jù)使用的key,可以用它來指定。默認是使用方法參數(shù)的值
  3. keyGenerator: key的生成器,可以自己指定key的生成器的組件id
  4. cacheManager:指定緩存管理器,或者 cacheResolver 指定獲取解析器
  5. condition:指定符合條件的情況下才緩存
  6. unless:否定緩存,當 unless 指定的條件為true,方法的返回值就不會被緩存
  7. sync:是否使用異步模式
  • 示例1)
image.png
image.png

2)

image.png

3)

image.png

4)

image.png

6)整合redis

  1. 引入spring-boot-starter-data-redis
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
復制代碼

2.application.yml配置 redis 連接地址

spring.redis.host=118.24.44.169
復制代碼

3.使用ReditTemplate操作redis

image.png

4.配置緩存

image.png

5.自定義redisTemplate

image.png

6.將自定義的redisTemplate注冊進RedisCacheManager

image.png

二、消息

*大多應用中,可通過消息服務中間件來提升系統(tǒng)異步通信、擴展解耦能力 *

消息服務中兩個重要概念:

  • 消息代理(message broker)
  • 目的地(destination)

當消息發(fā)送者發(fā)送消息以后,將由消息代理接管,消息代理保證消息傳遞到指定目的地。

消息隊列主要有兩種形式的目的地

  • 隊列(queue):點對點消息通信(point-to-point)
  • 主題(topic):發(fā)布(publish)/訂閱(subscribe)消息通信

點對點式

  • 消息發(fā)送者發(fā)送消息,消息代理將其放入一個隊列中,消息接收者從隊列中獲取消息內(nèi)容,消息讀取后被移出隊列
  • 消息只有唯一的發(fā)送者和接受者,但并不是說只能有一個接收者

發(fā)布訂閱式

  • 發(fā)送者(發(fā)布者)發(fā)送消息到主題,多個接收者(訂閱者)監(jiān)聽(訂閱)這個主題,那么就會在消息到達時同時收到消息

JMS(Java Message Service)JAVA消息服務

  • 基于JVM消息代理的規(guī)范。ActiveMQ、HornetMQ是JMS實現(xiàn)

AMQP(Advanced Message Queuing Protocol)

  • 高級消息隊列協(xié)議,也是一個消息代理的規(guī)范,兼容JMS
  • RabbitMQ是AMQP的實現(xiàn)
image.png

Spring支持

  • spring-jms提供了對JMS的支持
  • spring-rabbit提供了對AMQP的支持
  • 需要ConnectionFactory的實現(xiàn)來連接消息代理
  • 提供JmsTemplate、RabbitTemplate來發(fā)送消息
  • @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上監(jiān)聽消息代理發(fā)布的消息
  • @EnableJms、@EnableRabbit開啟支持

Spring Boot自動配置

  • JmsAutoConfiguration
  • RabbitAutoConfiguration

RabbitMQ

簡介
RabbitMQ是一個由erlang開發(fā)的AMQP(Advanved Message Queue Protocol)的開源實現(xiàn)。
核心概念

image.png
  • Message:
    消息,消息是不具名的,它由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對于其他消息的優(yōu)先權(quán))、delivery-mode(指出該消息可能需要持久性存儲)等。
  • Publisher:
    消息的生產(chǎn)者,也是一個向交換器發(fā)布消息的客戶端應用程序。
  • Consumer:
    消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序。
  • Exchange:
    交換器,用來接收生產(chǎn)者發(fā)送的消息并將這些消息路由給服務器中的隊列。不同類型的Exchange轉(zhuǎn)發(fā)消息的策略有所區(qū)別
  • direct(默認)
  • fanout
  • topic
  • headers
  • Queue:
    消息隊列,用來保存消息直到發(fā)送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列里面,等待消費者連接到這個隊列將其取走。
  • Binding:
    綁定,用于消息隊列和交換器之間的關(guān)聯(lián)。一個綁定就是基于路由鍵將交換器和消息隊列連接起來的路由規(guī)則,所以可以將交換器理解成一個由綁定構(gòu)成的路由表。Exchange 和Queue的綁定可以是多對多的關(guān)系。
  • Connection:
    網(wǎng)絡連接,比如一個TCP連接。
  • Channel:
    信道,多路復用連接中的一條獨立的雙向數(shù)據(jù)流通道。信道是建立在真實的TCP連接內(nèi)的虛擬連接,AMQP 命令都是通過信道發(fā)出去的,不管是發(fā)布消息、訂閱隊列還是接收消息,這些動作都是通過信道完成。因為對于操作系統(tǒng)來說建立和銷毀 TCP 都是非常昂貴的開銷,所以引入了信道的概念,以復用一條 TCP 連接。
  • Virtual Host:
    虛擬主機,表示一批交換器、消息隊列和相關(guān)對象。虛擬主機是共享相同的身份認證和加密環(huán)境的獨立服務器域。每個 vhost 本質(zhì)上就是一個 mini 版的 RabbitMQ 服務器,擁有自己的隊列、交換器、綁定和權(quán)限機制。vhost 是 AMQP 概念的基礎(chǔ),必須在連接時指定,RabbitMQ 默認的 vhost 是 / 。
  • Broker:
    表示消息隊列服務器實體

運行機制

  • AMQP 中的消息路由

AMQP 中消息的路由過程和 Java 開發(fā)者熟悉的 JMS 存在一些差別,AMQP 中增加了 Exchange 和Binding 的角色。生產(chǎn)者把消息發(fā)布到 Exchange 上,消息最終到達隊列并被消費者接收,而 Binding 決定交換器的消息應該發(fā)送到哪個隊列。

image.png
  • Exchange 類型

Exchange分發(fā)消息時根據(jù)類型的不同分發(fā)策略有區(qū)別,目前共四種類型:direct、fanout、topic、headers 。headers 匹配 AMQP 消息的* header 而不是路由鍵*, headers 交換器和 direct 交換器完全一致,但性能差很多,目前幾乎用不到了,所以直接看另外三種類型:

  1. direct
image.png

消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將消息發(fā)到對應的隊列中。路由鍵與隊列名完全匹配,如果一個隊列綁定到交換機要求路由鍵為“dog”,則只轉(zhuǎn)發(fā) routing key 標記為“dog”的消息,不會轉(zhuǎn)發(fā)“dog.puppy”,也不會轉(zhuǎn)發(fā)“dog.guard”等等。它是完全匹配、單播的模式。

2.fanout

image.png

每個發(fā)到 fanout 類型交換器的消息都會分到所有綁定的隊列上去。fanout 交換器不處理路由鍵,只是簡單的將隊列綁定到交換器上,每個發(fā)送到交換器的消息都會被轉(zhuǎn)發(fā)到與該交換器綁定的所有隊列上。很像子網(wǎng)廣播,每臺子網(wǎng)內(nèi)的主機都獲得了一份復制的消息。fanout 類型轉(zhuǎn)發(fā)消息是最快的。

3.topic

image.png

topic 交換器通過模式匹配分配消息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時隊列需要綁定到一個模式上。它將路由鍵和綁定鍵的字符串切分成單詞,這些單詞之間用點隔開。它同樣也會識別兩個通配符:符號“#”和符號“”。#匹配0個或多個單詞,匹配一個單詞。

整合RabbitMQ

  • 引入 spring-boot-starter-amqp
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
復制代碼
  • application.yml配置
spring.rabbitmq.host=118.24.44.169
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
復制代碼
  • 啟動類
image.png

示例

  • 自定義消息轉(zhuǎn)換器,以Jackson的形式轉(zhuǎn)換
@Configuration
public class MyAMQPConfig {
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}
復制代碼
  • 注入Bean
/**
  * 注入我們需要的兩個bean
  */
@Autowired
RabbitTemplate rabbitTemplate;
@Autowired
AmqpAdmin amqpAdmin;
復制代碼
  • 不同模式發(fā)送
image.png

Service 中接收消息示例
注意要在啟動類中開啟基于注解的RabbitMQ模式 :@EnableRabbit

image.png

三、檢索

我們的應用經(jīng)常需要添加檢索功能,開源的 ElasticSearch是目前全文搜索引擎的首選。他可以快速的存儲、搜索和分析海量數(shù)據(jù)。Spring Boot通過整合Spring Data ElasticSearch為我們提供了非常便捷的檢索功能支持;

Elasticsearch是一個分布式搜索服務,提供Restful API,底層基于Lucene,采用多shard(分片)的方式保證數(shù)據(jù)安全,并且提供自動resharding的功能,github等大型的站點也是采用了ElasticSearch作為其搜索服務

概念

以 員工文檔 的形式存儲為例:一個文檔代表一個員工數(shù)據(jù)。存儲數(shù)據(jù)到 ElasticSearch 的行為叫做索引,但在索引一個文檔之前,需要確定將文檔存儲在哪里。
一個 ElasticSearch 集群可以 包含多個 索引,相應的每個索引可以包含多個 類型 。 這些不同的類型存儲著多個 文檔 ,每個文檔又有 多個 屬性 。

類似關(guān)系:

  • 索引 ==== 數(shù)據(jù)庫
  • 類型 ==== 表
  • 文檔 ==== 表中的記錄
  • 屬性 ==== 列
image.png

整合ElasticSearch

SpringBoot 默認支持兩種技術(shù)來和 ES 交互

  • Jest(默認不生效)

導入jest的工具包

<dependency>
    <groupId>io.searchbox</groupId>
    <artifactId>jest</artifactId>
    <version>5.3.3</version>
</dependency>
復制代碼
  • SpringData ElasticSearch
  1. 版本適配問題升級SpringBoot版本安裝對應版本的ES
  2. 導入工具包
<!--SpringBoot默認使用SpringData ElasticSearch模塊進行操作-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
復制代碼
  1. 安裝Spring Data 對應版本的ElasticSearch
  2. application.properties配置
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=118.24.44.169:9301
復制代碼
  1. 測試
  • 注入Bean:
@Document(indexName = "cbuc",type = "book")
public class Book {
    private Integer id;
    private String bookName;
    private String author;
    //省略 get/set方法
}

public class Article {
    @JestId
    private Integer id;
    private String author;
    private String title;
    private String content;
    //省略 get/set 方法
}
復制代碼
  • 編寫 ElasticsearchRepository:
public interface BookRepository extends ElasticsearchRepository<Book,Integer> {
    //參照 https://docs.spring.io/spring-data/elasticsearch/docs/3.0.6.RELEASE/reference/html/
   public List<Book> findByBookNameLike(String bookName);
}
復制代碼
  • 引入所需要的Bean:
@Autowired
JestClient jestClient;
@Autowired
BookRepository bookRepository;
復制代碼

法1:
存入index:

Book book = new Book();
book.setId(1);
book.setBookName("西游記");
book.setAuthor("吳承恩");
bookRepository.index(book);
復制代碼

?。?/p>

for (Book book : bookRepository.findByBookNameLike("游")) {
    System.out.println(book);
}
復制代碼

法2:

//給Es中索引(保存)一個文檔:
Article article = new Article();
article.setId(1);
article.setTitle("測試");
article.setAuthor("cbuc");
article.setContent("測試檢索");
//構(gòu)建一個索引功能
Index index = new Index.Builder(article).index("cbuc").type("news").build();
//執(zhí)行
jestClient.execute(index);
復制代碼

測試搜索:

//查詢表達式
@Test
public void search(){
    //查詢表達式
    String json ="{\n" +
            "    \"query\" : {\n" +
            "        \"match\" : {\n" +
            "            \"content\" : \"hello\"\n" +
            "        }\n" +
            "    }\n" +
            "}";
    //更多操作: https://github.com/searchbox-io/Jest/tree/master/jest
    //構(gòu)建搜索功能
    Search search = new Search.Builder(json).addIndex("cbuc").addType("news").build();
    //執(zhí)行
    try {
        SearchResult result = jestClient.execute(search);
        System.out.println(result.getJsonString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}
復制代碼

四、任務

異步任務

在Java應用中,絕大多數(shù)情況下都是通過同步的方式來實現(xiàn)交互處理的。但是在處理與第三方系統(tǒng)交互的時候,容易造成響應遲緩的情況,之前大部分都是使用多線程來完成此類任務,其實,在Spring 3.x之后,就已經(jīng)內(nèi)置了@Async來完美解決這個問題。
兩個注解:

  • @EnableAysnc
  • @Aysnc

使用:

  1. 啟動類開啟異步注解功能
@EnableAsync  //開啟異步注解功能
@SpringBootApplication
public class Springboot04TaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot04TaskApplication.class, args);
    }
}
復制代碼

2.Service:

@Service
public class AsyncService {
    //告訴Spring這是一個異步方法
    @Async
    public void test(){
        try {
            //當前線程睡眠 3 秒頁面也能及時響應
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("處理數(shù)據(jù)中...");
    }
}
復制代碼

3.Controller:

@RestController
public class AsyncController {
    @Autowired
    AsyncService asyncService;
    @GetMapping("/hello")
    public String hello(){
        asyncService.test();
        return "success";
    }
}
復制代碼

定時任務

項目開發(fā)中經(jīng)常需要執(zhí)行一些定時任務,比如需要在每天凌晨時候,分析一次前一天的日志信息。Spring為我們提供了異步執(zhí)行任務調(diào)度的方式,提供TaskExecutor、TaskScheduler接口。
兩個注解:

  • @EnableScheduling
  • @Scheduled

cron表達式:

image.png
image.png

使用:

  1. 啟動類開啟基于注解的定時任務:
@EnableScheduling //開啟基于注解的定時任務
@SpringBootApplication
public class Springboot04TaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot04TaskApplication.class, args);
    }
}
復制代碼

2.Service:

image.png

郵件任務

使用

  1. 郵件發(fā)送需要引入spring-boot-starter-mail
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
復制代碼
  1. 定義MailProperties內(nèi)容,配置在application.properties中
spring.mail.username=(發(fā)送人qq賬號)
spring.mail.password=(發(fā)送人qq密碼)
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.ssl.enable=true
復制代碼

3.自動裝配JavaMailSender

image.png

五、分布式系統(tǒng)

單一應用架構(gòu)
當網(wǎng)站流量很小時,只需一個應用,將所有功能都部署在一起,以減少部署節(jié)點和成本。此時,用于簡化增刪改查工作量的數(shù)據(jù)訪問框架(ORM)是關(guān)鍵。
垂直應用架構(gòu)
當訪問量逐漸增大,單一應用增加機器帶來的加速度越來越小,將應用拆成互不相干的幾個應用,以提升效率。此時,用于加速前端頁面開發(fā)的Web框架(MVC)是關(guān)鍵。
流動計算架構(gòu)
當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現(xiàn),此時需增加一個調(diào)度中心基于訪問壓力實時管理集群容量,提高集群利用率。此時,用于提高機器利用率的資源調(diào)度和治理中心(SOA)是關(guān)鍵
分布式服務架構(gòu)
當垂直應用越來越多,應用之間交互不可避免,將核心業(yè)務抽取出來,作為獨立的服務,逐漸形成穩(wěn)定的服務中心,使前端應用能更快速的響應多變的市場需求。此時,用于提高業(yè)務復用及整合的分布式服務框架(RPC)是關(guān)鍵。

Zookeeper和Dubbo

ZooKeeper:
是一個分布式的,開放源碼的分布式應用程序協(xié)調(diào)服務。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。
Dubbo:
是Alibaba開源的分布式服務框架,它最大的特點是按照分層的方式來架構(gòu),使用這種方式可以使各個層之間解耦合(或者最大限度地松耦合)。從服務模型的角度來看,Dubbo采用的是一種非常簡單的模型,要么是提供方提供服務,要么是消費方消費服務,所以基于這一點可以抽象出服務提供方(Provider)和服務消費方(Consumer)兩個角色。

image.png

使用:

  • 安裝zookeeper作為注冊中心
  • 編寫服務提供者

引入dubbo和zkclient相關(guān)依賴

<dependency>
      <groupId>com.alibaba.boot</groupId>
      <artifactId>dubbo-spring-boot-starter</artifactId>
      <version>0.1.0</version>
</dependency>

<!--引入zookeeper的客戶端工具-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
      <groupId>com.github.sgroschupf</groupId>
      <artifactId>zkclient</artifactId>
      <version>0.1</version>
</dependency>
復制代碼

配置dubbo的掃描包和注冊中心地址

  dubbo.application.name=provider-ticket
  dubbo.registry.address=zookeeper://118.24.44.169:2181
  dubbo.scan.base-packages=cbuc.life.ticket.service
復制代碼

使用@Service發(fā)布服務

  @Component
  @Service //將服務發(fā)布出去  注意注解 Service是dubbo包下的
  public class TicketServiceImpl implements TicketService {
      @Override
      public String getTicket() {
          return "《我和我的祖國》";
      }
  }
復制代碼
  • 編寫服務消費者

引入dubbo和zkclient相關(guān)依賴

  <dependency>
      <groupId>com.alibaba.boot</groupId>
      <artifactId>dubbo-spring-boot-starter</artifactId>
      <version>0.1.0</version>
  </dependency>

  <!--引入zookeeper的客戶端工具-->
  <!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
  <dependency>
      <groupId>com.github.sgroschupf</groupId>
      <artifactId>zkclient</artifactId>
      <version>0.1</version>
  </dependency>
復制代碼

引用服務

  @Service
  public class UserService{
      @Reference    // 使用 Reference 引入服務
      TicketService ticketService;
      public void hello(){
          String ticket = ticketService.getTicket();
          System.out.println("調(diào)用買票服務:"+ticket);
      }
  }
復制代碼

Spring Boot和Spring Cloud

Spring Cloud是一個分布式的整體解決方案。Spring Cloud 為開發(fā)者提供了在分布式系統(tǒng)(配置管理,服務發(fā)現(xiàn),熔斷,路由,微代理,控制總線,一次性token,全局鎖,leader選舉,分布式session,集群狀態(tài))中快速構(gòu)建的工具,使用Spring Cloud的開發(fā)者可以快速的啟動服務或構(gòu)建應用、同時能夠快速和云平臺資源進行對接。
SpringCloud分布式開發(fā)五大常用組件

  • 服務發(fā)現(xiàn) —— Netflix Eureka
  • 客服端負載均衡 —— Netflix Ribbon
  • 斷路器 —— Netflix Hystrix
  • 服務網(wǎng)關(guān) —— Netflix Zuul
  • 分布式配置 —— Spring Cloud Config

使用

  • 引入Eureka注冊中心
<dependencyManagement>
    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

    </dependencies>
</dependencyManagement>
復制代碼
  • 配置application
server:
  port: 8761
eureka:
  instance:
    hostname: eureka-server  # eureka實例的主機名
  client:
    register-with-eureka: false #不把自己注冊到eureka上
    fetch-registry: false #不從eureka上來獲取服務的注冊信息
    service-url:
      defaultZone: http://localhost:8761/eureka/
復制代碼
  • 啟動類:
@EnableEurekaServer    
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
復制代碼
  • 創(chuàng)建provider

引入依賴

image.png

配置application

image.png

啟動類

image.png

service

image.png

controller

image.png
  • 創(chuàng)建consumer

引入依賴

image.png

配置application

image.png

啟動類

image.png

controller (通過使用RestTemplate調(diào)用服務)

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容