spring cloud(一) 從一個簡單的springboot服務(wù)開始

目錄

一、 為什么要使用微服務(wù)呢?它相比傳統(tǒng)的單體應(yīng)用有什么優(yōu)缺點呢?

從單體應(yīng)用和微服務(wù)的區(qū)別開始說起吧。簡單來說,傳統(tǒng)的單體應(yīng)用就是把項目所需的全部文件打包在一起,而微服務(wù)指的是將功能拆分成可以獨立運行的服務(wù),分開部署,服務(wù)之間通過一些輕量級的通信機制進行通信,這些服務(wù)一起構(gòu)建器整個系統(tǒng)。單從介紹來看微服務(wù)似乎有故意把簡單的問題復(fù)雜化的嫌疑,但是經(jīng)手過傳統(tǒng)的單體應(yīng)用的小伙伴肯定都深有體會,隨著項目的不斷開發(fā),項目的維護成本越來越高,很多功能相互調(diào)用,牽一發(fā)而動全身。不僅如此,編譯調(diào)試的過程也越來越慢。對于新的需求想用全新的技術(shù)棧提高開發(fā)效率也是非常困難。那么微服務(wù)的出現(xiàn)正是為了解決日益復(fù)雜龐大的單體應(yīng)用所導(dǎo)致的項目維護難,升級難的問題。
那么列舉一下微服務(wù)的優(yōu)點吧:

  1. 易于開發(fā)和維護:因為一個微服務(wù)通常只專注一個特定的業(yè)務(wù)功能,所以它的業(yè)務(wù)比較清晰,代碼量相對較少,開發(fā)和維護單個微服務(wù)相對簡單。
  2. 技術(shù)棧不受限:多個微服務(wù)之間通過輕量級的通信機制進行通信,每個微服務(wù)完全可以選擇更適合此項業(yè)務(wù)的技術(shù)棧。
  3. 更合理利用資源:多個微服務(wù)分開部署,可以針對io密集型的服務(wù),和cpu密集型的服務(wù)部署在特定的服務(wù)器上??舍槍δ硞€特定的服務(wù)升級內(nèi)存或增加節(jié)點。
  4. 復(fù)用性強: 就像堆積木一樣,通用性強的服務(wù)可以用在多個項目中。

微服務(wù)的確定:

  1. 運維困難: 更多的服務(wù)意味著需要投入更多的精力去維護項目,與傳統(tǒng)的只需要保證一個服務(wù)正常運行相比,保證成噸的服務(wù)正常運行顯然要更費勁。
  2. 分布式固有的復(fù)雜性:在分布式系統(tǒng)中,網(wǎng)絡(luò)延遲,分布式事務(wù),服務(wù)之間的容錯等都是技術(shù)挑戰(zhàn)。
  3. 接口的維護成本高: 微服務(wù)之間通過api進行通信,如果修改某個服務(wù)的api將導(dǎo)致其他使用此api的服務(wù)做出相應(yīng)的調(diào)整。
  4. 重復(fù)的工作: 一些功能有可能多個服務(wù)都需要,此時可能會多個服務(wù)都實現(xiàn)同樣的功能。

二、 微服務(wù)帶來了曙光,也帶來了挑戰(zhàn),那么應(yīng)對這些挑戰(zhàn)我們需要一些設(shè)計原則

  1. 單一職責(zé)原則
    一個服務(wù)只干一件事了。
  2. 服務(wù)自治原則
    每個服務(wù)得有基本的自理能力吧。開發(fā)、測試、部署、運行都應(yīng)該可以獨立完成。
  3. 輕量級通信原則
    一定要輕啊,帶寬很重要。也要滿足跨平臺的特性,常用的協(xié)議有:REST,AMQP,STOMP,MQTT
  4. 微服務(wù)的粒度
    如何確定服務(wù)的邊界這是嘗嘗爭論的焦點。需要考慮的因素很多,如業(yè)務(wù)本身,團隊的情況等等。

三、本系列實現(xiàn)微服務(wù)的技術(shù)選擇

  1. spring-cloud 可以很好的和springboot一起工作,屬于主流的解決方案,文檔豐富社區(qū)活躍。
  2. docker 出于方便,快捷以及易用性考慮選擇docker作為微服務(wù)的運行平臺。

四、 先從springboot開始實現(xiàn)一個簡單的服務(wù)間調(diào)用吧

場景介紹: 我們實現(xiàn)兩個服務(wù),一個生產(chǎn)者服務(wù),一個消費者服務(wù)。消費者調(diào)用生產(chǎn)者并獲取一個用戶信息。
技術(shù)選擇:java版本:1.8,springboot版本:2.0.5.RELEASE,ORM:JPA,數(shù)據(jù)庫:h2,依賴管理工具:maven,開發(fā)工具:idea

1. 新建一個項目product_server

新建空項目product_server

2. 添加pom依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yshmsoft</groupId>
    <artifactId>product_server</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3. 在classpath下建立schema.sql建表語句和data.sql數(shù)據(jù)語句,并添加如下內(nèi)容:

// schema.sql
drop table user if exists;
create table user(
  id bigint generated by default as identity,
  name varchar(20),
  age int(3),
  money decimal(10,2),
  primary key(id)
);

//data.sql 
insert into user(id,name,age,money) values (1, 'user1', 18, 233.22);
insert into user(id,name,age,money) values (2, 'user2', 22, 21133.22);
insert into user(id,name,age,money) values (3, 'user3', 34, 23333.22);
insert into user(id,name,age,money) values (4, 'user4', 54, 555233.22);
insert into user(id,name,age,money) values (5, 'user5', 19, 2332313.22);
insert into user(id,name,age,money) values (6, 'user6', 33, 2335522.22);

4. 新建User實體

package com.yshmsoft.entity;

import javax.persistence.*;
import java.math.BigDecimal;
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column
    private String name;
    @Column
    private Integer age;
    @Column
    private BigDecimal money;
    //getter setter
}

5. 新建UserDao

package com.yshmsoft.dao;

import com.yshmsoft.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserDao extends JpaRepository<User,Long> {
}

6.新建UserController

package com.yshmsoft.controller;

import com.yshmsoft.dao.UserDao;
import com.yshmsoft.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    UserDao userDao;
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userDao.findById(id);
    }
}

7.編寫application.yml

server:
  port: 8080
spring:
  datasource:
    platform: h2
    schema: classpath:schema.sql
    data: classpath:data.sql
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
logging:
  level:
    root: info
    org.hibernate: info

8.添加啟動類

  package com.yshmsoft;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProductApplocation {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplocation.class, args);
    }
}

9. 運行項目并訪問http://localhost:8080/1

訪問結(jié)果

10. 新建一個comsume_server模塊

新建模塊

comsume_server模塊

11. 同上一個項目一樣配置pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yshmsoft</groupId>
    <artifactId>consome_server</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

12. 新建User類

package com.yshmsoft.entity;

import java.math.BigDecimal;

public class User {
    private Long id;
    private String name;
    private Integer age;
    private BigDecimal money;
    // getter setter
}

13.創(chuàng)建消費者Controller

package com.yshmsoft.controller;

import com.yshmsoft.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class UserController {
    @Autowired
    RestTemplate restTemplate; //spring 提供的RestTemplate,方便調(diào)用Rest接口
    @GetMapping("/user/{id}")
    User getUserById(@PathVariable Long id) {
        User user = restTemplate.getForObject("http://localhost:8080/" + id, User.class);
        return user;
    }
}

14. 創(chuàng)建配置文件application.yml

server:
  port: 8000
logging:
  level:
    root: info

15. 創(chuàng)建啟動類

package com.yshmsoft;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumeApplication {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumeApplication.class, args);
    }
}

16 啟動項目并訪問http://localhost:8000/user/1

訪問成功示例

到此完成第一個示例的編寫。

五、 談一談上面的示例

完成了一個簡單的微服務(wù)之間調(diào)用,上面這種微服務(wù)的實現(xiàn)方式會面臨什么問題呢?

  1. 上面的例子中生產(chǎn)者的api是寫死的,當(dāng)生產(chǎn)者的api地址改變時消費者要跟著改變。
  2. 這種方式服務(wù)的伸縮性比較差,服務(wù)對單個服務(wù)的依賴性較強
  3. 每次新建一個服務(wù)都要配置api地址心累。

接下來我們開始spring cloud的學(xué)習(xí)吧,看看spring cloud為我們提供的解決方案。敬請期待。

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

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

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