SpringCloud基础入门

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

随着项目的越来越大,每次启动编译时间将会越来越长,这对于开发、测试、部署带来极大的影响,大大降低了效率。这时,关于微服务的模式就兴起了。


一、SpringCloud概念

1. 是什么

Spring cloud是一个基于Spring Boot实现的服务治理工具包,用于微服务架构中管理和协调服务的。微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被技术选型,独立开发,独立部署,独立运维,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。

2. 组成部分

服务注册发现(注册中心)——Netflix Eureka : 帮我们管理服务的通信地址(ip,端口)
客户端负载均衡——Netflix Ribbon\Feign : 解决服务的调用的
断路器——Netflix Hystrix :解决微服务故障的,保护微服务的
服务网关——Netflix Zuul :统一访问入口,微服务的大门(安保部门)
分布式配置——Spring Cloud Config :统一管理微服务的配置

二、搭建微服务场景

1.搭建环境

搭建一个maven项目,配置pom文件

   <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>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
        <springboot.version>2.0.5.RELEASE</springboot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
        </dependencies>
    </dependencyManagement>

2. 服务提供者

新建子模块,服务提供者,maven项目,编写接口。此处偷懒将业务代码直接写到controller,应该是写到service层的。

@RestController
@RequestMapping("/provider")
public class UserController {

    //    @Autowired
   //    private IUserService userService;
    @GetMapping("/user/{id}") //user/1
    public User getUser(@PathVariable("id") Long id) {

        // 正常应该调用service获取用户,现在模拟一下
        return new User(id, "zs");
    }
}

3. 服务消费者

同理建立子模块,服务消费者。这里用到了框架自带的RestTemplate发送请求。需要先在入口类注入。

@Configuration // <beans></beans>
public class CfgBean {

    @Bean //<bean class="org.springframework.web.client.RestTemplate"></bean>
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}



@RestController
@RequestMapping("/consumer")
public class UserController {

    //多个方法调用只需改一处就ok
    public static  final String URL_PREFIX = "http://localhost:8001";

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        //调用远程服务 http请求
        String url = URL_PREFIX+"/provider/user/"+id;
        return restTemplate.getForObject(url,User.class );
    }
}

4. 测试

分别启动,通过调用消费者得到提供者的返回值。

三、Eureka注册中心

上面我们是在消费者中写死了提供者的URL,这肯定在实际中是不可取的,所以我们可以调用Eureka将服务提供者统一管理。

1. 搭建Eureka

创建一个普通maven项目

pom

<!--springboot支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<!--Eureka服务端支持-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

yml配置

server:
  port: 7001
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false #是否要注册到eureka
    fetchRegistry: false #表示是否从Eureka Server获取注册信息
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置

入口类

@SpringBootApplication
@EnableEurekaServer //标识是eureka服务端
public class EnrekaServerApplication_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EnrekaServerApplication_7001.class);
    }
}

2. 服务提供者注册到Eureka

添加依赖

 <!--eureka客户端支持 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

yml

eureka:
  client:
    service-url:
     defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
 instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

入口类

@SpringBootApplication
@EnableEurekaClient //表示是eureka的客户端
public class UserProviderApplication_8001 {
    public static void main(String[] args) {
        SpringApplication.run(UserProviderApplication_8001.class);
    }
}

3. 服务消费者调用

添加依赖

 <!--eureka客户端支持 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

yml

eureka:
  client:
    service-url:
     defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
 instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

入口类

@SpringBootApplication
@EnableEurekaClient //表示是eureka的客户端
public class UserProviderApplication_8001 {
    public static void main(String[] args) {
        SpringApplication.run(UserProviderApplication_8001.class);
    }
}

服务调用

 @Autowired
private DiscoveryClient discoveryClient;// Eureka客户端,可以获取到服务实例信息

// String baseUrl = "http://localhost:8081/user/";
        // 根据服务名称,获取服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        // 因为只有一个UserService,因此我们直接get(0)获取
        ServiceInstance instance = instances.get(0);
        // 获取ip和端口信息
        String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
       this.restTemplate.getForObject(baseUrl + id, User.class)

4. 集群

  • Eureka集群
    修改yml,选择不同的激活可达到集群的目的
eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1011/eureka,http://eureka3:1012/eureka
spring:
  profiles:
    active: eureka1
---
#eureka1第一个Eureka
spring:
  profiles: eureka1
  application:
    name: eureka1
server:
  port: 1010  #端口
eureka:
  instance:
    hostname: eureka1  #主机
    instance-id: eureka1:1010
---
#eureka1第一个Eureka
spring:
  profiles: eureka2
  application:
      name: eureka2
server:
  port: 1011  #端口
eureka:
  instance:
    hostname: eureka2  #主机
    instance-id: eureka2:1011
---
#eureka3第一个Eureka
spring:
  profiles: eureka3
  application:
      name: eureka3
server:
  port: 1012  #端口
eureka:
  instance:
    hostname: eureka3  #主机
    instance-id: eureka3:1012
  • 服务提供者集群
    同理修改yml配置

四、Ribbon负载均衡

为了提供并发量,有时同一个服务提供者可以部署多个(商品服务)。这个客户端在调用时要根据一定的负责均衡策略完成负载调用。

1. 是什么

简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。

2. 负载均衡测试

依赖

   <!--客户端负载均衡实现 ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

消费者入口类修改

    @Bean
    @LoadBalanced //开启负载均衡
    public RestTemplate getRestTemplate(){
        return  new RestTemplate();
    }

服务消费

@RestController
@RequestMapping("/consumer")
public class UserController {

    //多个方法调用只需改一处就ok
    //public static  final String URL_PREFIX = "http://localhost:8001";
    public static  final String URL_PREFIX = "http://USER-PROVIDER"; //通过服务名从注册中心获取服务列表,通过负载均衡调用

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        //调用远程服务 http请求
        String url = URL_PREFIX+"/provider/user/"+id;
        return restTemplate.getForObject(url,User.class );
    }
}

测试
会出现轮询的效果

2. 负载均衡策略

部分

  • RoundRobinRule(默认):简单轮询服务列表来选择服务器。
  • WeightedResponseTimeRule:为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
  • RandomRule:随机选择一个可用的服务器。

在这里插入图片描述

五、Feign负载均衡

前面的可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

Feign是一个声明式的Web Service客户端,它的目的就是让Web
Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

总起来说,Feign具有如下特性:
可插拔的注解支持,包括Feign注解和JAX-RS注解;
支持可插拔的HTTP编码器和解码器;
支持Hystrix和它的Fallback;
支持Ribbon的负载均衡;
支持HTTP请求和响应的压缩。

1. 搭建

依赖,将ribbon修改为feign

    <!--feign的支持-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

yml

server:
  port: 9003
eureka:
  client:
    registerWithEureka: false #不注册到Eureka,不在注册中心显示
    service-url:
      #defaultZone: http://localhost:7001/eureka
      defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka

调用服务的名字,要和服务提供者里面访问地址和参数等保持一致。

//调用服务名字
@FeignClient(value = "USER-PROVIDER")
@RequestMapping("/provider")
public interface UserCilent {
    @RequestMapping("/user/{id}") //user/1
     User getUser(@PathVariable("id") Long id);
}

入口类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "上面服务接口包") 
public class UserConsumerFeign9002Application {

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

消费代码

@RestController
@RequestMapping("/consumer")
public class UserController {
    @Autowired
    private UserCilent userCilent;
    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        System.out.println(userCilent.getClass());
        return userCilent.getUser(id);
    }
}

六、Hystrix断路器

Hystrix是保证微服务群健壮框架,做了隔离,熔断,降级等操作.最终达到不会由于某一个服务出问题而导致雪崩现象,让整体群死掉。

1、简介

Hystrix是国外知名的视频网站Netflix所开源的非常流行的高可用架构框架。Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题。

Hystrix “豪猪”,具有自我保护的能力。hystrix 通过如下机制来解决雪崩效应问题。

资源隔离(限流):包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。

熔断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。

降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。

缓存:提供了请求缓存、请求合并实现。

2. 实现

服务提供依赖

<!--断路器-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

yml

server:
  port: 4020
spring:
  application:
    name: user-provider
eureka:
  instance:
    prefer-ip-address: true #显示eureka客户端真实ip
  client:
    service-url:
     #defaultZone: http://localhost:1010/eureka #告诉服务提供者要把服务注册到哪
     #eureka集群环境
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1011/eureka,http://eureka3:1012/eureka

入口类
在这里插入图片描述
在这里插入图片描述

3. Feign实现

Feign自己封装了Hytrix,不需要再导入jar
yml

server:
  port: 9003
eureka:
  client:
    registerWithEureka: false #不注册到Eureka,不在注册中心显示
    service-url:
      defaultZone: http://localhost:7001/eureka
feign:
   hystrix:
       enabled: true #开启熔断支持
   client:
    config:
      remote-service:           #服务名,填写default为所有服务
        connectTimeout: 3000
        readTimeout: 3000
hystrix:
  command:
      default:
        execution:
          isolation:
            thread:
              timeoutInMilliseconds: 3000

降级处理

package cn.itsource.springcloud.client;

import cn.itsource.springcloud.domain.User;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
//UserClient 表示对那个接口进行托底处理
public class UserClientHystrixFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public User getUser(Long id) {
                return new User(id,"出异常,请联系管理员!");
            }
        };
    }
}

//调用服务名字
@FeignClient(value = "USER-PROVIDER",fallbackFactory = UserClientHystrixFallbackFactory.class)
@RequestMapping("/provider")
public interface UserClient {
    @RequestMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);

}

七、 Zuul网关

在这里插入图片描述

1. 搭建

依赖

<!--springboot支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

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

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

yml

server:
  port: 2010
spring:
  application:
    name: zuul-gateway
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1011/eureka,http://eureka3:1012/eureka
  instance:
    instance-id: zuul:2010
    prefer-ip-address: false

入口类

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulGatewayApp2010 {

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

路由配置

zuul:
  routes:
    myUser.serviceId: user-provider # 服务名
    myUser.path: /myUser/** # 把myUser打头的所有请求都转发给user-provider
  ignored-services: "*" #所有服务都不允许以服务名来访问
  prefix: "/services" #加一个统一前缀

2. 过滤器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

自定义过滤器

@Component
public class LoginFilter extends ZuulFilter{
    @Override
    public String filterType() {
        // 登录校验,肯定是在前置拦截
        return "pre";
    }

    @Override
    public int filterOrder() {
        // 顺序设置为1
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        // 返回true,代表过滤器生效。
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        // 登录校验逻辑。
        // 1)获取Zuul提供的请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 2) 从上下文中获取request对象
        HttpServletRequest req = ctx.getRequest();
        // 3) 从请求中获取token
        String token = req.getParameter("access-token");
        // 4) 判断
        if(token == null || "".equals(token.trim())){
            // 没有token,登录校验失败,拦截
            ctx.setSendZuulResponse(false);
            // 返回401状态码。也可以考虑重定向到登录页。
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        // 校验通过,可以考虑把用户信息放入上下文,继续向后执行
        return null;
    }
}

3.负载均衡与熔断

Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:

zuul:
  retryable: true
ribbon:
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
  MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMillisecond: 3000 # 熔断超时时长:3000ms

八、SpringCloud Config分布式配置中心

1. 是什么

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。

2. 和githee集成

2.1 服务端配置

在这里插入图片描述

2.2 创建子模块

依赖

<dependencies>
    <!--springboot支持-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <!--eureka客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--配置中心支持-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>

yml

server:
  port: 1299
eureka:
  client:
    service-url:
      defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka # 集群

  instance:
    prefer-ip-address: true
spring:
  application:
    name: spring-cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: gitee的uri
          username: xxx
          password: xxx

入口类

@SpringBootApplication
@EnableEurekaClient //加入注册中心
@EnableConfigServer //启用配置服务端
public class ConfigServerApplication_1299 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication_1299.class);
    }
}

测试
http://localhost:1299/application-user/test
http://localhost:1299/application-user/dev

总结

简单的springcloud就差不多入门了,还有更多更深入的等着我们。。。。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值