Spring Cloud 学习记录

今天是2020-10-6日

打开spring cloud的主页(https://spring.io/projects/spring-cloud#overview)

首先就看到最新的版本号 : Spring Cloud  Hoxton.SR8

大版本号:Hoxton (从ABCDEFGH往上排),这就是H版

小版本号: SNAPSHOT:快照版本;随时可能修改 M:MileStone,M1表示第1个里程碑版本,一般同时标注PRE,表示预览版版。 SR:Service Release,SR1表示第1个正式版本,一般同时标注GA:(GenerallyAvailable),表示稳定版本。

Table 1. Release train Spring Boot compatibility
Release TrainBoot Version

Hoxton

2.2.x, 2.3.x (Starting with SR5)

Greenwich

2.1.x

Finchley

2.0.x

Edgware

1.5.x

Dalston

1.5.x

打开第二个tab页  LEARN ,看到这个版本列表

Hoxton.SR8 CURRENT GA

Reference Doc.

API Doc.
2020.0.0-SNAPSHOT SNAPSHOTReference Doc.API Doc.
2020.0.0-M3 PREReference Doc.API Doc.
Hoxton.BUILD-SNAPSHOT SNAPSHOTReference Doc.API Doc.
Greenwich.SR6 GAReference Doc.API Doc.
Greenwich.BUILD-SNAPSHOT SNAPSHOTReference Doc.API Doc.

打开 Reference Doc. 超级链接,可以看到和Spring Boot的版本对应关系

Release Train Version: Hoxton.SR8

Supported Boot Version: 2.3.3.RELEASE

 

第一章  创建服务注册中心 eureka-server

微服务架构,最基本的,就是要有一个服务注册和服务发现中心。之前用eureka(官方不再维护了),还可以使用zookeeper,etcd,consul,nacos。

建立父工程,即多module maven工程,注意pom的packaging 为 pom, 不是jar

父pom.xml

<?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>gaofeng</groupId>
  <artifactId>springcloud</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>springcloud</name>
  <description>springcloud</description>
  <modules>
    <module>eurekaserver</module>
    <module>app1</module>
    <module>app2</module>
    <module>zuul</module>
  </modules>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.boot.version>2.3.3.RELEASE</spring.boot.version>
    <spring.cloud.version>Hoxton.SR8</spring.cloud.version>
    <spring.cloud.alibaba.version>2.2.3.RELEASE</spring.cloud.alibaba.version>
    <env>dev</env>
  </properties>
  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
子pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  
  <parent>
    <groupId>gaofeng</groupId>
    <artifactId>springcloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  
  <artifactId>eurekaserver</artifactId>
 
  <dependencies>
        <!-- 引入 Spring Cloud Netflix Eureka Server 相关依赖,将 Eureka 作为注册中心的服务器,并实现对其的自动配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
  </dependencies>
  
<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
					<configuration>
						<classifier>exec-${env}</classifier>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build> 

</project>
eurekaserver/src/main/resources/application.yml

server:
  port: 8761 # 设置 Eureka-Server 的端口

spring:
  application:
    name: eureka-server

eureka:
  client:
    register-with-eureka: false # 不注册到 Eureka-Server,默认为 true
    fetch-registry: false # 不从 Eureka-Server 获取注册表,默认为 true
package org.eurekaserver;

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

// EurekaServer管理页面  http://127.0.0.1:8761

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}
mvn clean install
java -jar target/eurekaserver-0.0.1-SNAPSHOT-exec-dev.jar

第二章 创建第一个微服务 app1

pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>gaofeng</groupId>
    <artifactId>springcloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <artifactId>app1</artifactId>
  
  <dependencies>
        <!-- 引入 Spring 相关依赖,并实现对其的自动配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  </dependencies>
  <build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                    <configuration>
                        <classifier>exec-${env}</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
  </build> 
</project>
app1/src/main/resources/application.yml

server:
  port: 10002 # 设置 app1 的端口

spring:
  application:
    name: app1

eureka:
  client:
    register-with-eureka: true # 注册到 Eureka-Server,默认为 true
    fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址
package org.app1;

import java.util.Random;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@SpringBootApplication
@EnableDiscoveryClient
public class App1 {
    public static void main(String[] args) {
        SpringApplication.run(App1.class, args);
    }
}
@RestController
class TestController2 {
    private int id = new Random().nextInt();
    @GetMapping("/echo")
    public String echo(String name) {
        return "provider:"+id+":" + name;
    }
}
$ java -jar target/app1-0.0.1-SNAPSHOT-exec-dev.jar

$ curl -is http://127.0.0.1:10002/echo?name=gg
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 22
Date: Tue, 06 Oct 2020 15:57:07 GMT

provider:-537651807:gg

第三章 微服务之间如何调用rest接口

再启动一个app1的实例,端口号改为10004

$ java -jar target/app1-0.0.1-SNAPSHOT-exec-dev.jar --server.port=10004

Instances currently registered with Eureka

ApplicationAMIsAvailability ZonesStatus
APP1n/a (2)(2)UP (2) - DESKTOP-EIPDTAD:app1:10002 , DESKTOP-EIPDTAD:app1:10004
APP3n/a (1)(1)UP (1) - DESKTOP-EIPDTAD:app3:10005
server:
  port: 10005 # 设置 app3 的端口

spring:
  application:
    name: app3

eureka:
  client:
    register-with-eureka: true # 注册到 Eureka-Server,默认为 true
    fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址
package org.app2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient
@SpringBootApplication
public class App3 {
    public static void main(String[] args) {
        SpringApplication.run(App3.class, args);
    }
  @Configuration
  public class RestTemplateConfiguration {
      @Bean 
      @LoadBalanced
      public RestTemplate restTemplate() {
          return new RestTemplate();
      }
  }
    @RestController
    static class TestController {
        @Autowired
        private RestTemplate restTemplate;
        
        @GetMapping("/hello")
        public String hello(String name) {
            String response = restTemplate.getForObject("http://app1/echo?name="+name, String.class);
            // 返回结果
            return "consumer:" + response;
        }
    }
}

curl -is http://127.0.0.1:10005/hello?name=gg

他的本质过程其实是:

package org.app2;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class App2 {

    public static void main(String[] args) {
        SpringApplication.run(App2.class, args);
    }
    
    @Configuration
    public class RestTemplateConfiguration {
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }

    @RestController
    static class TestController {

        @Autowired
        private DiscoveryClient discoveryClient;
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        @GetMapping("/hello")
        public String hello(String name) {
            // <1> 获得服务 `demo-provider` 的一个实例
            ServiceInstance instance;
            if (System.currentTimeMillis()%2==0) {
                // 获取服务 `demo-provider` 对应的实例列表
                List<ServiceInstance> instances = discoveryClient.getInstances("app1");
                System.out.println(instances);
                // 选择第一个
                instance = instances.size() > 0 ? instances.get(0) : null;
            } else {
                instance = loadBalancerClient.choose("app1");
            }
            // <2> 发起调用
            if (instance == null) {
                throw new IllegalStateException("获取不到实例");
            }
            String targetUrl = instance.getUri() + "/echo?name=" + name;
            System.out.println(targetUrl);
            String response = restTemplate.getForObject(targetUrl, String.class);
            // 返回结果
            return "consumer:" + response;
        }
    }
}

第四章 使用另外一种(声明式)http客户端openFegin(老的Fegin已经不更新了) 

关键点1:@FeignClient("app1") 
关键点2:public String echo(@RequestParam("name") String name); 必须加@RequestParam("name")
验证方法:curl -s 127.0.0.1:10005/feign?name=gf

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

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class App4 {
    public static void main(String[] args) {
        SpringApplication.run(App4.class,args);
    }
}
@RestController
class RemoteServer {
    @Autowired
    RemoteApi remoteApi;

    @RequestMapping(value = "/feign",method = RequestMethod.GET)
    public String remoteServer(@RequestParam String name){
       return remoteApi.echo(name);
    }
}

@FeignClient("app1")
interface RemoteApi{
    @GetMapping(value = "/echo")
    public String echo(@RequestParam("name") String name); 
}

设置Fegin的超时时间,在yml中增加

ribbon:
  ReadTimeout: 1000
  ConnectTimeout: 1000

打印Fegin的日志,在yml中增加

logging:
  level:
    ROOT: INFO
    #针对指定的类 设置输出级别
    org.app2.*: debug
feign:
  client:
    config:
      default:
        loggerLevel: FULL

第五章  限流、降级、熔断  hystrix

服务降级有很多种降级方式!如开关降级、限流降级、熔断降级! 

在yml中开启熔断机制
feign:
  hystrix:
    enabled: true
代码修改
@FeignClient(value="app1",fallback = FallbackImpl.class)
interface RemoteApi{
    @GetMapping(value = "/echo2")  //故意把url写错,当Feign调用这个url出错时,会返回FallbackImpl
    public String echo(@RequestParam("name") String name); 
}

@Service
class FallbackImpl implements RemoteApi{ //编写熔断的处理类
    public String echo(String name) {
        return "error error error error error";
    }
}

 

第六章 consul

G:\gaofeng\consul_1.8.4_windows_amd64

1、启动 consul agent -dev

2、打开界面  http://localhost:8500/

3、注册服务
curl http://127.0.0.1:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
 "ID": "userServiceId2",
 "Name": "userService",
 "Tags": [ "primary",  "v1" ],
 "Address": "127.0.0.1",
 "Port": 8000,
 "EnableTagOverride": false,
 "Check": {
  "DeregisterCriticalServiceAfter": "90m",
  "HTTP": "http://www.baidu.com",
  "Interval": "10s"
 }
}'
curl http://127.0.0.1:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
 "ID": "userServiceId1",
 "Name": "userService",
 "Tags": [ "primary",  "v1" ],
 "Address": "127.0.0.1",
 "Port": 8000,
 "EnableTagOverride": false,
 "Check": {
  "DeregisterCriticalServiceAfter": "90m",
  "HTTP": "http://www.baidu.com",
  "Interval": "10s"
 }
}'
4、查询服务
curl http://127.0.0.1:8500/v1/catalog/service/userService
5、服务更新:id是唯一的,更新时保持id不变即可

app1consul的pom

  <dependencies>
    <dependency><!-- 健康检查依赖于此包 -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
  
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
     </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>     
  </dependencies>
yaml文件
server:
  port: 8501 # 设置 微服务 的端口

spring:
  application:
    name: App1Consul
  cloud:
    consul:
      host: localhost
      port: 8500
    discovery:
      serviceName: App1Consul #注册到consul的服务名称

@SpringBootApplication
@EnableDiscoveryClient
public class App1Consul {
    static final int id = new Random().nextInt(100);
    
    public static void main( String[] args ){
        SpringApplication.run(App1Consul.class, args);
    }
}
@RestController
class Desk{
    @GetMapping("hello")
    public String hello(String name) {
        return "\n"+App1Consul.id + " : " + name;
    }
}
@SpringBootApplication
@EnableDiscoveryClient
public class App2Consul {
    public static void main( String[] args ){
        SpringApplication.run(App2Consul.class, args);
    }
}
@Configuration
class RestTemplateConfiguration {
  @Bean 
  @LoadBalanced
  public RestTemplate restTemplate() {
      return new RestTemplate();
  }
}

@RestController
class Controller1{
    @Autowired RestTemplate restTemplate;
    
    @GetMapping("hello")
    public String hello(@RequestParam("name") String name) {
        String response = restTemplate.getForObject("http://App1Consul/hello?name="+name, String.class);
        return response;
    }
}

app2consul的端口为8621
效果测试: curl -s 127.0.0.1:8601/hello?name=gg

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值