主頁 > 後端開發 > SpringCloud學習筆記

SpringCloud學習筆記

2021-04-13 06:49:25 後端開發

本文主要介紹 SpringCloud 的入門

一、SpringCloud 的五大組件

(需要牢牢記住他們,現在混個眼熟,下面會詳細介紹,)

image

自學參考檔案:

  • SpringCloud 官方檔案(漢化版):https://springcloud.cc/spring-cloud-dalston.html
  • SpringCloud中國社區:http://springcloud.cn/
  • SpringCloud中文網:https://springcloud.cc

自學參考文章:

  • 一文詳解微服務架構:https://www.cnblogs.com/skabyy/p/11396571.html

自學參考知乎各個大神們的回答:

  • 微服務架構是什么?:https://www.zhihu.com/question/65502802

自學參考視頻:

  • kuangstudy:https://www.kuangstudy.com/course/play/1321005531116863490

二、什么是微服務

Spring官網:https://spring.io/
image

微服務(Microservice Architecture) 是近幾年流行的一種架構思想,關于它的概念很難一言以蔽之,究竟什么是微服務呢?我們在此參考ThoughtWorks 公司的首席科學家 Martin Fowler 于2014年提出的一段話:

原文:https://martinfowler.com/articles/microservices.html

中文:https://www.cnblogs.com/liuning8023/p/4493156.html

就目前而言,對于微服務,業界沒有一個統一的標準定義,通常而言,微服務架構是一種架構模式,或者說是一種架構風格,它提倡將單一的應用程式劃分為一組小的服務,每個服務運行在其獨特的自己的行程內,服務之間互相協調,互相配置,為用戶提供最終價值,服務之間采用輕量級的通信機制互相溝通,每個服務都圍繞著具體的業務進行構建,并且能夠被獨立的部署到生產環境中,另外,應盡量避免統一的,集中式的服務管理機制,對具體的一個服務而言,應根據業務背景關系,選擇適合的語言,工具對其進行構建,可以有一個非常輕量級的集中管理來協調這些服務,可以用不同的語言來撰寫服務,也可以使用不同的資料庫, (牢牢記住上面這段概念,幾乎每句話都有微服務的關鍵點)

三、傳統開發模式 VS 微服務

  • 傳統的web開發方式

一般被稱為Monolithic(單體式開發),所有的功能打包在一個 WAR包里,基本沒有外部依賴(除了容器),部署在一個JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有邏輯,

image

優點:
集中式管理,開發簡單,功能都在本地,沒有分布式的管理和呼叫,

缺點:
1.效率低,開發都在同一個專案改代碼,互相等待,沖突不斷;
2.穩定性差,一個微小的問題,可能導致整個程式掛掉;
3.維護性難,代碼高耦合,內部關系難以摸清楚;
4.擴展性差,無法滿足高并發下的業務需求;

  • 隨著業務的發展,移動端興起

image

這一階段,架構設計存在著很多不合理的地方:
1.網站和移動端存在著很多相同業務邏輯的重復代碼;
2.資料庫被多個應用依賴,無法重構和優化;
3.資料有時候通過資料庫共享,有時候通過介面呼叫傳輸,介面呼叫關系雜亂;
4.單個應用為了給其他應用提供介面,設計得越來越復雜,包含本不屬于它得邏輯;
5.應用之間界限模糊,功能歸屬混亂,出現問題后各部門職責很難劃分,出現分歧或爭端;
6.所有的應用都在一個資料庫上操作,資料庫出現性能瓶頸;
7.管理后臺保障級別比較低,添加新的功能可能影響到其他應用;
8.開發、部署、維護、升級愈發困難;

  • 下一階段,除去大量的冗余代碼

image

在這一階段,服務已經被拆分開了,但是資料庫依然是共用的,會出現一些問題:
1.資料庫性能瓶頸,而且存在一定的風險;
2.資料庫表結構可能被多個服務依賴,維護困難;

  • 提高系統的實時性,再次升級架構(微服務)

image

此時,拆分后的各個服務可以采用異構的技術,比如,資料分析服務可以使用資料倉庫作為持久化層,以便于高效地做一些統計計算;促銷服務訪問比較頻繁,因此可以加入快取機制,

微服務,它是具體解決某一個問題/提供落地對應服務的一個服務應用,狹義的看,可以看作是IDEA中的一個個微服務工程,或者Moudel,IDEA 工具里面使用Maven開發的一個個獨立的小Moudel,它具體是使用SpringBoot開發的一個小模塊,專業的事情交給專業的模塊來做,一個模塊就做著一件事情,強調的是一個個的個體,每個個體完成一個具體的任務或者功能,

微服務的優點:
1.單一職責原則;
2.每個服務足夠內聚,足夠小,代碼容易理解;
3.開發效率高,一個服務可能就是專一的只干一件事;
4.微服務能夠被小團隊單獨開發,這個團隊只需2-5個開發人員組成;
5.松耦合,無論是在開發階段或部署階段都是獨立的;
6.可以使用不同的語言開發;
7.易于和第三方集成,微服務允許容易且靈活的方式集成自動部署,通過持續集成工具,如jenkins,Hudson,bamboo;
8.每個微服務都有自己的存盤能力,可以有自己的資料庫,也可以有統一的資料庫;

微服務的缺點:
1.開發人員要處理分布式系統的復雜性;
2.多服務運維難度,隨著服務的增加,運維的壓力也在增大;
3.各個服務間的通信成本問題;
4.整個應用分散成多個服務,定位故障相對困難;
5.一個服務故障可能產生雪崩效用,導致整個系統故障;

整體解決思路如下:
image

四、SpringCloud入門

官網:http://projects.spring.io/spring-cloud/

image

SpringCloud沒有采用數字編號的方式命名版本號,而是采用了倫敦地鐵站的名稱,同時根據字母表的順序來對應版本時間順序,比如最早的Realse版本:Angel,第二個Realse版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Hoxton SR4 CURRENT GA通用穩定版,

  • 微服務技術堆疊有那些?
微服務技術條目 落地技術
服務開發 SpringBoot、Spring、SpringMVC等
服務配置和管理 Netfix公司的Archaius、阿里的Diamond等
服務注冊與發現 Eureka、Consul、Zookeeper等
服務呼叫 Rest、PRC、gRPC
服務熔斷器 Hystrix、Envoy等
負載均衡 Ribbon、Nginx等
服務介面呼叫(客戶端呼叫服務的簡化工具 Fegin等
訊息佇列 Kafka、RabbitMQ、ActiveMQ等
服務配置中心管理 SpringCloudConfig、Chef等
服務路由(API網關) Zuul等
服務監控 Zabbix、Nagios、Metrics、Specatator等
全鏈路追蹤 Zipkin、Brave、Dapper等
資料流操作開發包 SpringCloud Stream(封裝與Redis,Rabbit,Kafka等發送接收訊息)
時間訊息總站 SpringCloud Bus
服務部署 Docker、OpenStack、Kubernetes等
  • 各微服務框架對比
功能點/服務框架 Netflix/SpringCloud Motan gRPC Thrit Dubbo/DubboX
功能定位 完整的微服務框架 RPC框架,但整合了ZK或Consul,實作集群環境的基本服務注冊發現 RPC框架 RPC框架 服務框架
支持Rest 是,Ribbon支持多種可拔插的序列號選擇
支持RPC 是(Hession2)
支持多語言 是(Rest形式)
負載均衡 是(服務端zuul+客戶端Ribbon),zuul-服務,動態路由,云端負載均衡Eureka(針對中間層服務器) 是(客戶端) 是(客戶端)
配置服務 Netfix Archaius,Spring Cloud Config Server 集中配置 是(Zookeeper提供)
服務呼叫鏈監控 是(zuul),zuul提供邊緣服務,API網關
高可用/容錯 是(服務端Hystrix+客戶端Ribbon) 是(客戶端) 是(客戶端)
典型應用案例 Netflix Sina Google Facebook
社區活躍程度 一般 一般 2017年后重新開始維護,之前中斷了5年
學習難度 中等
檔案豐富程度 一般 一般 一般
其他 Spring Cloud Bus為我們的應用程式帶來了更多管理端點 支持降級 Netflix內部在開發集成gRPC IDL定義 實踐的公司比較多

  • Rest 搭建學習環境

1.創建父工程 springcloud (使用 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.zhou</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>springcloud-consumer-dept-80</module>
        <module>springcloud-provider-dept-8001</module>
        <module>springcloud-api</module>
    </modules>
    <!--打包方式 pom -->
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringCloud的依賴-->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>runtime</scope>
            </dependency>
            <!--SpringBoot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--資料庫-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.5</version>
            </dependency>
            <!--SpringBoot 啟動器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--日志測驗-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <!--Maven 資源過濾問題-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>

注意:父工程為 springcloud,其下有多個子 module

2.創建子模塊 springcloud-api,它只負責接管 pojo

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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.zhou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-api</artifactId>

    <dependencies>
        <!--當前的module自己需要的依賴,如果父類中已經配置了版本,這里就不需要寫了-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

3.在SQLyog中創建資料庫 db01

image

idea連接此資料庫并創建一些欄位和資料

image

insert into dept (dname, db_source) VALUES ('開發部',DATABASE());
insert into dept (dname, db_source) VALUES ('設計部',DATABASE());
insert into dept (dname, db_source) VALUES ('人事部',DATABASE());
insert into dept (dname, db_source) VALUES ('運營部',DATABASE());
insert into dept (dname, db_source) VALUES ('企劃部',DATABASE());
insert into dept (dname, db_source) VALUES ('編輯部',DATABASE());

4.創建物體類

package com.zhou.springcloud.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@NoArgsConstructor
@Accessors(chain = true) //鏈式編程,默認 boolean chain() default false;
public class Dept implements Serializable { //Dept 物體類

    private Long deptno;//主鍵
    private String dname;
    //這個資料存在那個資料庫的欄位,微服務,一個服務對應一個資料庫,同一個資訊可能存在不同的資料庫
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }
}

5.創建子模塊 springcloud-provider-dept-8001 (服務的提供者)

子模塊 springcloud-provider-dept-8001 的整體專案結構如下:

image

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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.zhou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <dependencies>
        <!--我們需要拿到物體類,所以要配置 api module-->
        <dependency>
            <groupId>com.zhou</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--熱部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
</project>

application.yaml

server:
  port: 8001

#mybatis 配置
mybatis:
  type-aliases-package: com.zhou.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

#speing 配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--開啟二級快取-->
        <setting name="cacheEnabled" value="https://www.cnblogs.com/1693977889zz/archive/2021/04/12/true"/>
    </settings>
</configuration>

DeptMapper 介面

package com.zhou.springcloud.mapper;

import com.zhou.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface DeptMapper {
    boolean addDept(Dept dept);
    Dept queryById(@Param("id") Long id);
    List<Dept> queryAll();
}

DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhou.springcloud.mapper.DeptMapper">
    <insert id="addDept" parameterType="Dept">
        insert into dept (dname, db_source)
        values (#{dname},DATABASE());
    </insert>
    <select id="queryById" parameterType="Long" resultType="Dept">
        select * from dept where deptno=#{id};
    </select>
    <select id="queryAll" resultType="Dept">
        select * from dept
    </select>
</mapper>

DeptService 介面

package com.zhou.springcloud.service;
import com.zhou.springcloud.pojo.Dept;
import java.util.List;

public interface DeptService {
    boolean addDept(Dept dept);
    Dept queryById(Long id);
    List<Dept> queryAll();
}

DeptServiceImpl.java

package com.zhou.springcloud.service;

import com.zhou.springcloud.mapper.DeptMapper;
import com.zhou.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptMapper deptMapper;
    @Override
    public boolean addDept(Dept dept) {
        return deptMapper.addDept(dept);
    }

    @Override
    public Dept queryById(Long id) {
        return deptMapper.queryById(id);
    }

    @Override
    public List<Dept> queryAll() {
        return deptMapper.queryAll();
    }
}

DeptController.java

package com.zhou.springcloud.controller;

import com.zhou.springcloud.pojo.Dept;
import com.zhou.springcloud.service.DeptService;
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.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

//提供Restful服務
@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @GetMapping("/dept/add")//方便此時的測驗,這里用了Get,沒有用Post
    public boolean addDept(Dept dept) {
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept getDept(@PathVariable("id") Long id){
        return deptService.queryById(id);
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
}

6.啟動類

package com.zhou.springcloud;

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

//啟動類
@SpringBootApplication
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

7.Run 測驗

訪問:http://localhost:8001/dept/list (測驗成功!)

訪問:http://localhost:8001/dept/get/1 (測驗成功!)

訪問:http://localhost:8001/dept/add?dname=地獄部 (測驗成功!)

查詢資料庫
image


1.創建子模塊 springcloud-consumer-dept-80 (服務的消費者)

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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.zhou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-dept-80</artifactId>

    <dependencies>
        <!--不需要連接資料庫,需要物體類+web-->
        <dependency>
            <groupId>com.zhou</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
</dependencies>
</project>

application.yml

server:
  port: 80

ConfigBean.java

package com.zhou.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration //@Configuration 相當于 spring中 applicationContext.xml
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

RestTemplate 部分原始碼:
image

DeptConsumerController.java

package com.zhou.springcloud.controller;

import com.zhou.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Controller
public class DeptConsumerController {
    //理解:消費者,不應該有 service 層
    //RestTemplate.... 供我們直接呼叫就可以了,注冊到Spring中
    @Autowired
    private RestTemplate restTemplate;

    //http://localhost:8081/dept/add?dname=地獄部
    private static final String REST_URL_PREFIX="http://localhost:8081";

    @RequestMapping("/consumer/dept/add")
    @ResponseBody
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept,Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    @ResponseBody
    public Dept get(@PathVariable("id") Long id){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }

    @RequestMapping("/consumer/dept/list")
    @ResponseBody
    public List<Dept> list(){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
    }
}

DeptConsumer_80.java 啟動類

package com.zhou.springcloud;

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

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

2.修改:springcloud-provider-dept-8001 它的 DeptController.java類的addDept()方法

(否則,在下面測驗中,使用瀏覽器url傳參的方式來插入資料時,資料庫中顯示dname的值為null)
image

    @PostMapping("dept/add")
    public boolean addDept(@RequestBody Dept dept){
        return deptService.addDept(dept);
    }

3.啟動

首先,啟動服務的提供者 springcloud-provider-dept-8001 的啟動類 DeptProvider_8001
其次,啟動服務的消費者 springcloud-consumer-dept-80 的啟動類 DeptConsumer_80

image

4.Run 測驗

訪問:http://localhost/consumer/dept/list

image

訪問:http://localhost/consumer/dept/get/5

image

訪問:http://localhost/consumer/dept/add?dname=架構師3

image

查看資料庫

image

五、Eureka 服務注冊中心

  • Eureka 定義

Eureka 是Netflix的一個子模塊,也是核心模塊之一,Eureka是基于REST的服務,用于定位服務,以實作云端中間件層服務發現和故障轉移,服務注冊與發現對于微服務來說是非常重要的,有了服務注冊與發現,只需要使用服務的識別符號,就可以訪問到服務,而不需要修改服務呼叫的組態檔了,功能類似于Dubbo的注冊中心,比如Zookeeper,

image

在云中,應用程式不能總是知道其他服務的確切位置,一個服務注冊中心,比如Netflix Eureka,或者一個sidecar解決方案,比如HashiCorp Consul,都會有所幫助,springcloud為流行的注冊中心提供DiscoveryClient實作,比如Eureka、Consul、Zookeeper,甚至Kubernetes的內置系統,還有一個springcloud負載均衡器可以幫助您在服務實體之間小心地分配負載,

官方介紹:https://spring.io/projects/spring-cloud-netflix
image

springcloudnetflix通過自動配置并系結到Spring環境和其他Spring編程模型習慣用法,為Spring啟動應用程式提供Netflix作業系統集成,通過一些簡單的注釋,您可以快速啟用和配置應用程式中的常見模式,并使用經過測驗的Netflix組件構建大型分布式系統,提供的模式包括服務發現(Eureka)、斷路器(Hystrix)、智能路由(Zuul)和客戶端負載平衡(Ribbon)

  • Dubbo 和 SpringCloud對比

最大區別:Spring Cloud 拋棄了Dubbo的RPC通信,采用的是基于HTTP的REST方式,
二者解決的問題域不一樣:Dubbo的定位是一款RPC框架,而SpringCloud的目標是微服務架構下的一站式解決方案,

Dubbo SpringCloud
服務注冊中心 Zookeeper Spring Cloud Netfilx Eureka
服務呼叫方式 RPC REST API
服務監控 Dubbo-monitor Spring Boot Admin
斷路器 不完善 Spring Cloud Netfilx Hystrix
服務網關 Spring Cloud Netfilx Zuul
分布式配置 Spring Cloud Config
服務跟蹤 Spring Cloud Sleuth
訊息總堆疊 Spring Cloud Bus
資料流 Spring Cloud Stream
批量任務 Spring Cloud Task

嚴格來說,這兩種方式各有優劣,雖然從一定程度來說,SpringCloud犧牲了服務呼叫的性能,但也避免了上面提到的原生RPC帶來的問題,而且REST相比RPC更為靈活,服務提供方和呼叫方的依賴只依靠一紙契約,不存在代碼級別的強依賴,這個優點在當下強調快速演化的微服務環境下,顯得更加合適,

  • Eureka基本的架構

1.Springcloud 封裝了Netflix公司開發的Eureka模塊來實作服務注冊與發現 (對比Zookeeper).
2.Eureka采用了C-S的架構設計,EurekaServer作為服務注冊功能的服務器,他是服務注冊中心.
3.系統中的其他微服務,使用Eureka的客戶端連接到EurekaServer并維持心跳連接,(方便監控系統中各個微服務是否正常運行)

image

  • 與Dubbo架構對比

image

  • 構建 Eureka 代碼示例

1.創建子模塊 springcloud-eureka-7001

pom 依賴

<artifactId>springcloud-eureka-7001</artifactId>
	<!--匯入依賴-->
<dependencies>
	<!--spring-cloud-starter-netflix-eureka-server 依賴-->
	<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		<version>2.2.7.RELEASE</version>
	</dependency>
	<!--熱部署-->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
	</dependency>
</dependencies>

application.yaml

server:
  port: 7001

# Eureka 部署
eureka:
  instance:
    # Eureka服務端的實體名字
    hostname: localhost
  client:
    # 表示是否向 Eureka 注冊中心注冊自己(這個模塊本事是服務器,所以不需要)
    register-with-eureka: false
    # fetch-registry 如果為 false,則表示自己為注冊中心,客戶端的為 true
    fetch-registry: false
    # Eureka 監控頁面
    service-url:
      #public static final String DEFAULT_URL = "http://localhost:8761/eureka/";
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

啟動類 EurekaServer_7001.java

package com.zhou.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @Auther: zhouzhou
 * @Description: 啟動之后,訪問 http://127.0.0.1:7001/
 */
@SpringBootApplication
@EnableEurekaServer //服務端的啟動類,可以接受別人注冊進來
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

Run 測驗

報錯資訊:Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationPropertiesBean

image

觀察報錯資訊,得出有可能是版本沖突問題,解決辦法是將 spring-cloud-starter-netflix-eureka-server 依賴的版本降為2.1.4.RELEASE

【注意】:報錯原因是版本問題,可以選擇到官網查看版本是否一致,比如 SPRINGCLOUD的版本,我的父依賴用的是GREENWICH.SR1
你如果用了HOXTON.SR10 甚至更新的,請自行查找對應的版本依賴,

繼續測驗,Run 成功!

image

訪問:http://localhost:7001/

image

  • Eureka 服務注冊 資訊配置以及自我保護機制

配置 Eureka-client

1.在上面創建的子模塊 springlouc-provider-dept-8001 的 pom 中添加依賴

<!--Eureka:spring-cloud-starter-netflix-eureka-client 依賴-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	<version>2.1.4.RELEASE</version>
</dependency>

2.application.yaml 中添加設定

# Eureka配置:配置注冊中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

3.啟動類中使用 @EnableEurekaClient注解

package com.zhou.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

//啟動類
@SpringBootApplication
@EnableEurekaClient
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

4.先啟動7001服務端,再啟動8001客戶端進行測驗,訪問監控頁:http://localhost:7001/ 產看結果如圖,成功

image

5.修改 Eureka 上的默認描述資訊

# Eureka配置:配置注冊中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 # 修改eureka上的默認描述資訊
    prefer-ip-address: true

查看:
image

6.配置關于服務加載的監控資訊(springcloud-provider-dept-8001)

沒配置之前,訪問:springcloud-provider-dept8001
image

跳出的頁面如下:

image

配置服務加載的監控資訊步驟如下:

pom.xml中添加依賴

<!--actuator完善監控資訊-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yaml 中添加配置

# info配置
info:
  # 專案名稱
  app.name: zhouzhou-springcloud
  # 公司名稱
  company.name: blog.zhouzhou.com

7.Run 再重繪頁面,繼續訪問:springcloud-provider-dept8001,跳出頁面如下

image

  • EureKa自我保護機制

默認情況下,如果Eureka Server在90秒內沒有接收到某個微服務實體的心跳,會注銷該實體,但是在微服務架構下服務之間通常都是跨行程呼叫,網路通信往往面臨很多問題,比如微服務狀態正常,網路磁區故障,導致此實體被注銷,

固定時間內大量實體被注銷,可能會嚴重威脅某個微服務架構的可用性,為了解決這個問題,Eureka開發了自我保護機制,

Eureka Server在運行期間會去統計心跳失敗比例在15分鐘之內是否低于85%,如果低于85%,Eureka Server即進入自我保護機制,

Eureka Server觸發自我保護機制后,頁面會出現提示:

image

Eureka Server進入自我保護機制,會出現以下幾種情況:
(1)Eureka不再從注冊串列中移除因為長時間沒收到心跳而應該過期的服務;
(2)Eureka仍然能夠接受新服務的注冊和查詢,但是不會被同步到其它節點上(即保證當前節點依然可用);
(3)當網路穩定后,當前實體新的注冊資訊會被同步到其它節點上;

Eureka自我保護機制是為了防止誤殺服務而提供的一種機制,當個別客戶端出現心跳失聯時,則認為是客戶端的問題,剔除客戶端;當Eureka 捕獲到大量的心跳失敗時,則認為可能是網路問題,進入自我保護機制;當客戶端心跳恢復時,Eureka會自動退出自我保護機制,

如果在保護期內剛好這個服務提供者非正常下線了,此時服務消費者就會拿到一無效的服務實體,則會呼叫失敗,對于這個問題需要服務消費者要有一些容錯機制,比如重試,斷路器等,

  • 注冊進來的微服務,獲取其中的一些資訊(團隊開發)

1.查看 EurekaDiscoveryClient 原始碼:

image

2.觀察 DiscoveryClient 原始碼:

image

3.在 springcloud-provider-dept-8001 的 DeptController.java中添加 discovery() 方法

//DiscoveryClient 可以用來獲取一些配置的資訊,得到具體的微服務
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 獲取一些注冊進來的微服務的資訊
     * @return
     */
    @GetMapping("dept/discovery")
    public Object discovery(){
        //獲取微服務串列清單
        System.out.println("getServices()=>"+discoveryClient.getServices());
        System.out.println("description()=>"+discoveryClient.description());

        List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost()+"\t"+ //主機名稱
                    instance.getPort()+"\t"+ //埠號
                    instance.getUri()+"\t"+ //uri
                    instance.getInstanceId() //服務id
            );
        }
        return  this.discoveryClient;
    }

4.上面 discoveryClient.getInstances()的引數 ---> SPRINGCLOUD-PROVIDER-DEPT
image

5.主啟動類中加入 @EnableDiscoveryClient 注解

package com.zhou.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

//啟動類
@SpringBootApplication
//@EnableEurekaClient 開啟Eureka客戶端注解,在服務啟動后自動向注冊中心注冊服務
@EnableEurekaClient
//@EnableDiscoveryClient 開啟服務發現客戶端的注解,可以用來獲取一些配置的資訊,得到具體的微服務
@EnableDiscoveryClient
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

6.Run 測驗
先啟動 springcloud-eureka-7001 中的住啟動類 EurekaServer_7001,
再啟動 springcloud-provider-dept-8001 中的主啟動類 DeptProvider_8001,

訪問:http://localhost:7001/ 一切正常

image

繼續訪問:http://localhost:8001/dept/discovery

image

springcloud-provider-dept-8001 控制臺輸出:

image


  • Eureka:集群環境配置

整體結構如下:
image

1.新建 子模塊springcloud-eureka-7002 和 springcloud-eureka-7003

2.添加 pom 依賴 (與springcloud-eureka-7001相同)

3.application.yml配置 (與springcloud-eureka-7001相同)
(埠號用各自的 7001、7002和7003)

4.主啟動類 (與springcloud-eureka-7001相同)

5.集群成員相互關聯
配置一些自定義本機名字,在C:\Windows\System32\drivers\etc找到本機hosts檔案,在hosts檔案最后加上,要訪問的本機名稱(默認是localhost)
image

127.0.0.1     eureka7001.com
127.0.0.1     eureka7002.com
127.0.0.1     eureka7003.com

【注意】:修改hosts檔案后一定要保存,如果遇到 修改hosts檔案無權限的問題,參考下圖配置:

image

6.修改 各自的 application.yml 的配置

(1)設定各自的 服務端的實體名字(hostname)
(2)設定各自的 集群(關聯)

springcloud-eureka-7001 的 application.yaml

server:
  port: 7001

# Eureka 部署
eureka:
  instance:
    # Eureka服務端的實體名字
    hostname: eureka7001.com
  client:
    # 表示是否向 Eureka 注冊中心注冊自己(這個模塊本事是服務器,所以不需要)
    register-with-eureka: false
    # fetch-registry 如果為 false,則表示自己為注冊中心,客戶端的為 true
    fetch-registry: false
    # Eureka 監控頁面
    service-url:
      # public static final String DEFAULT_URL = "http://localhost:8761/eureka/";
      # 單機:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(關聯):7001關聯 7002、7003
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

springcloud-eureka-7002 的 application.yaml

server:
  port: 7002

eureka:
  instance:
    # Eureka服務端的實體名字
    hostname: eureka7002.com
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      # 集群(關聯):7002關聯 7001、7003
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

springcloud-eureka-7003 的 application.yaml

server:
  port: 7003

eureka:
  instance:
    # Eureka服務端的實體名字
    hostname: eureka7003.com
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      # 集群(關聯):7003關聯 7001、7002
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

7.通過 springcloud-provider-dept-8001 的yaml組態檔,修改 Eureka 的配置:配置服務注冊中心地址

image

# Eureka配置:配置注冊中心地址
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 # 修改eureka上的默認描述資訊
    prefer-ip-address: true

8.模擬集群搭建完畢,(可以把一個專案掛載到三個服務器上了)

測驗,訪問:http://localhost:7001/
image

測驗,訪問:http://localhost:7002/
image

測驗,訪問:http://localhost:7003/
image


  • Eureka與Zookeeper 的對比

1.CAP原則

  • RDBMS (MySQL\Oracle\sqlServer) ===> ACID
  • NoSQL (Redis\MongoDB) ===> CAP

2.ACID是什么

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 隔離性
  • D (Durability) 持久性

3.CAP是什么

  • C (Consistency) 一致性
  • A (Availability) 可用性
  • P (Partition tolerance) 磁區容錯性

CAP的三進二:CA、AP、CP

4.CAP理論的核心
一個分布式系統不可能同時很好的滿足一致性,可用性和磁區容錯性這三個需求
根據CAP原理,將NoSQL資料庫分成了滿足CA原則,滿足CP原則和滿足AP原則三大類

  • CA:單點集群,滿足一致性,可用性的系統,通常可擴展性較差
  • CP:滿足一致性,磁區容錯的系統,通常性能不是特別高
  • AP:滿足可用性,磁區容錯的系統,通常可能對一致性要求低一些

5.作為分布式服務注冊中心,Eureka比Zookeeper好在哪里?

著名的CAP理論指出,一個分布式系統不可能同時滿足C (一致性) 、A (可用性) 、P (容錯性),由于磁區容錯性P再分布式系統中是必須要保證的,因此我們只能再A和C之間進行權衡,

Zookeeper 保證的是 CP —> 滿足一致性,磁區容錯的系統,通常性能不是特別高
Eureka 保證的是 AP —> 滿足可用性,磁區容錯的系統,通常可能對一致性要求低一些

  • Zookeeper保證的是CP

當向注冊中心查詢服務串列時,我們可以容忍注冊中心回傳的是幾分鐘以前的注冊資訊,但不能接收服務直接down掉不可用,也就是說,服務注冊功能對可用性的要求要高于一致性,但zookeeper會出現這樣一種情況,當master節點因為網路故障與其他節點失去聯系時,剩余節點會重新進行leader選舉,問題在于,選舉leader的時間太長,30-120s,且選舉期間整個zookeeper集群是不可用的,這就導致在選舉期間注冊服務癱瘓,在云部署的環境下,因為網路問題使得zookeeper集群失去master節點是較大概率發生的事件,雖然服務最終能夠恢復,但是,漫長的選舉時間導致注冊長期不可用,是不可容忍的,

  • Eureka保證的是AP

Eureka看明白了這一點,因此在設計時就優先保證可用性,Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的作業,剩余的節點依然可以提供注冊和查詢服務,而Eureka的客戶端在向某個Eureka注冊時,如果發現連接失敗,則會自動切換至其他節點,只要有一臺Eureka還在,就能保住注冊服務的可用性,只不過查到的資訊可能不是最新的,除此之外,Eureka還有之中自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現了網路故障,此時會出現以下幾種情況:

(1)Eureka不在從注冊串列中移除因為長時間沒收到心跳而應該過期的服務
(2)Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其他節點上 (即保證當前節點依然可用)
(3)當網路穩定時,當前實體新的注冊資訊會被同步到其他節點中

因此,Eureka可以很好的應對因網路故障導致部分節點失去聯系的情況,而不會像zookeeper那樣使整個注冊服務癱瘓,

六、Ribbon:負載均衡(基于客戶端)

七、Feign:負載均衡(基于服務端)

八、Hystrix:服務熔斷

九、Zull路由網關

十、Spring Cloud Config 分布式配置

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/275334.html

標籤:其他

上一篇:阿里云maxcompute系列--用pyodps+odps sql實作釘釘機器人預警推送

下一篇:Qt信號槽原始碼剖析(二)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more