深入学习SpringCloud微服务

SpringCloud

一,写一个小例子,引出springcloud微服务

新建一个项目microservice,maven项目,这个项目是父项目,所以只建一个java project即可。

[外链图片转存失败(img-vlXkD4MP-1568537333557)(D:\文件笔记\image\1568018765301.png)]

name标签上边加上配置,声明该项目为springboot项目

  <modules>
    <module>provider-user</module>
    <module>consumer-order</module>
  </modules>
  <!--将当前项目声明为springboot项目-->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
  </parent>
  <name>microserviceTwo</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

加上下面的依赖,否则可能会报错。

 <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>

然后在父项目上新建两个Module,分别是提供者provider-user和消费者consumer-order

提供者provider-user

提供者配置pom文件,加上一下配置标志为springboot

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

然后新建application.yml配置文件

server:
  port: 7900 #程序启动后的端口
spring:
  application:
    name: provider-user #应用名称,别名

写一个User实体类,加上构造器,接下来要传值

package com.qianlong.User;
import java.util.Date;

public class User {
    private Long id;
    private Date date;
    public User(){
        super();
    }
    public User(Long id) {
        this.id = id;
        this.date=new Date();
    }
}

写一个controller,去拿User的信息

@RestController
public class UserController {

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id){
        return new User(id);
    }
}

启动项目的启动类ProviderUser

很明显,在浏览器输入地址:localhost:7900/user/1可以得到一个user的信息

然后再新建一个Module

消费者consumer-order

和提供者模块一样,加上依赖标志为springboot项目

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
</dependency>

同样,这个模块也写一个同上的user类,以及构造方法

然后写controller

@RestController
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;//spring提供的一个用于访问rest接口的模板对象

    @Value("${user.url}")//去配置文件中去取值然后赋值给url
    private String url;
    //private String url="http://localhost:7900/user/";

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Long id){
        //访问提供者,获取数据
        User user = restTemplate.getForObject(url + id, User.class);//通过访问rest获取到json数据,然后转换为user对象
        return user;
    }
}

说明:springboot项目的配置文件application.yml默认在resources文件夹下,把resources文件夹标记为资源文件后项目可自动读取到配置文件。

这样子的话,在浏览器访问localhost:8900/order/1时,也可以得到user的信息。上面通过RestTemplate模板对象的getForObject方法可以访问其他Module的路径,由消费者指向提供者。

这也体现出了springCloud微服务的一点感觉,可以把业务模块进行拆分。但是上面的不是springcloud项目,现在开始写springcloud项目。

二,springCloud项目

在上面的项目的基础上进行改动,首先在父项目的pom中加入springCloud依赖标注为springCloud项目。

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.M9</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

父项目中的每一个Module都是一个服务。

这里要引入Eureka,它是一个服务注册中心,是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

需要把服务都注册到EurekaServer中。

创建EurekaServer

在父项目中新建一个Module,起名为Eureka,作为注册服务中心。

pom中加入EurekaServer依赖

下面的安全依赖是进入eureka的url时要输入用户名和密码,启动eureka会在控制台打印出一个默认的随机密码,也可以在配置文件中进行配置用户名和密码

 <!-- eureka server依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>
        <!--安全依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

[外链图片转存失败(img-x9uCLinN-1568537471617)(D:\文件笔记\image\1568025846777.png)]
EurekaServer中写启动类,加上注解@EnableEurekaServer把当前项目标记为eureka server

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

然后创建文件resources并标志成资源文件,然后新建application.yml文件,加入配置

server:
  port: 10000
  # 因为当前的eureka是单机的,所以需要做一些配置
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      # defaultZone: http://localhost:10000/eureka  # 访问eureka路径
      defaultZone: http://user:123@localhost:10000/eureka  # 访问eureka路径
security:
  basic:
    enabled: true # 开启安全配置,也就是需要密码,如果不需要设置成false,注意,这个参数必须放在application.yml中,不允许放在bootstrap.yml中
  user:
    name: user
    password: 123 # 在配置了用户名和密码之后,我们可以修改地址的访问风格为curl风格

然后通过localhost:10000访问

[外链图片转存失败(img-F03TdQC4-1568537333559)(D:\文件笔记\image\1568026217477.png)]

提供者和消费者注册到eureka

在提供者provider-user的项目中加入eureka-client依赖,标记为客户端(EurekaServer为服务端

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

application.yml加入eureka client的配置,路径和EurekaServer的路径相同。

server:
  port: 7900 #程序启动后的端口
spring:
  application:
    name: provider-user #应用名称,别名
eureka:
  client:
    service-url:
      defaultZone:  http://user:123@localhost:10000/eureka

最后在启动类上加上注解@EnableEurekaClient标志为eureka的客户端。

测试是否已注册到EurekaServer

先启动EurekaServer模块的启动类,再启动提供者provider-user的启动类,再浏览器url输入地址:localhost:10000,进入到eureka页面,会看到提供者已注册到EurekaServer中。

[外链图片转存失败(img-4QOhoQC3-1568537333559)(D:\文件笔记\image\1568031248364.png)]

EurekaClient得到url

在提供者provider-user模块的controller中注入EurekaClient,并写方法,info方法中的内容可以获取到服务的url路径。

@RestController
public class UserController {
    @Autowired
    private EurekaClient eurekaClient;

    @GetMapping("/eurekaInfo")
        public String info(){
            InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);
            return instanceInfo.getHomePageUrl();
        }

然后先启动eureka服务端,再启动provider-user客户端,输入路径localhost:10000,点击下面服务的路径

[外链图片转存失败(img-zkoHtKS8-1568537333560)(D:\文件笔记\image\1568032086317.png)]

会得到服务对应的url

[外链图片转存失败(img-bnGIceAd-1568537333560)(D:\文件笔记\image\1568032110220.png)]

和上面一样,把消费者consumer-order模块也注册到eureka服务中。

这样,重新刷新eureka页面,就会看到已经有两个服务了,点击消费者服务的路径,输入消费者consumer-order模块中的controller方法路径到url上面,可以出查询user的信息,方法正常使用。
在这里插入图片描述

消费者动态获取提供者的url

上面在消费者consumer-order的方法中调用提供者provider-user的方法的url是写死的。

回顾:是把url在配置文件中写死然后再通过@Value("${user.url}")获取。

这里要动态获取到提供者的url

在消费者controller中注入EurekaClient,然后通过方法获取到对应服务的url

@RestController
public class OrderController {
    @Autowired
    private EurekaClient eurekaClient;

    @Autowired
    private RestTemplate restTemplate;//spring提供的一个用于访问rest接口的模板对象

    //@Value("${user.url}")//去配置文件中去取值然后赋值给url
    //private String url;
    //private String url="http://localhost:7900/user/";

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Long id){
        InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);
        String url= instanceInfo.getHomePageUrl();
        //访问提供者,获取数据
        User user = restTemplate.getForObject(url + "/user/" + id, User.class);//通过访问rest获取到json数据,然后转换为user对象
        return user;
    }
}

然后运行EurekaServer服务端,再分别启动提供者的客户端provider-user和消费者的客户端consumer-order的启动类,然后访问localhost:10000,点击消费者服务的路径,重新编辑路径为http://laptop-oi5lg6ou:8900/order/2,(2是id参数,重点不是2)回车访问,依然可以查看到user的信息。

在这里插入图片描述

Ribbon基本使用

Ribbon是在消费者立场使用的。

复制一份消费者模块consumer-order,改名为consumer-order-ribbon,并导入项目。

操作说明:在idea中右键模块名,选择show in explorer打开所在文件夹,然后复制重命名,需要更改pom文件中的模块名,然后idea自动把模块引入项目中,更改父项目的pom文件,就是添加一个<Module>consumer-order-ribbon</Module>

consumer-order-ribbon消费者的启动类加上注解@RibbonClient("PROVIDER-USER")

这个注解是启用ribbon,括号中为提供者的服务名,并对该服务provider-user进行负载均衡。

@RibbonClient("PROVIDER-USER") //启用ribbon并对provider-user进行负载均衡

然后再orderController中写方法,调用provider-user服务的user/?的方法,取得user的信息。

如下代码,在getForObject方法中的url路径参数,变为服务名,而不是上面的真实的路径地址。

 @Autowired
    private RestTemplate restTemplate;//spring提供的一个用于访问rest接口的模板对象

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Long id){

        //访问提供者,获取数据
        User user = restTemplate.getForObject( "http://PROVIDER-USER/user/" + id, User.class);//通过访问rest获取到json数据,然后转换为user对象
        return user;
    }

启动项目,启动顺序(eureka服务端,provider-user提供者,ribbon消费者)

运行项目,进入到eureka中点击ribbon的服务地址,然后修改后面的路径为order/1,回车,可以查到user的信息。其实ribbon的作用最能体现的是把url真实路径改为了服务名

Ribbon负载均衡算法

consumer-order-ribbon消费者模块加上负载均衡算法

默认的负载均衡算法

consumer-order-ribbon消费者模块写test方法,如果启动多个提供者模块的服务的话(改一个端口号另外启动),进到eureka页面,点击consumer-order-ribbon服务地址,然后修改为test路径,执行test方法,会看到后台打印出这几个提供者的服务名、ip地址、端口号,并且是轮询打印

 @Autowired
    private LoadBalancerClient loadBalancerClient;//注入负载均衡客户端

    @GetMapping("/test")
    public String test(){
        ServiceInstance instance = loadBalancerClient.choose("PROVIDER-USER");//查找对应服务的实例,会通过负载均衡的算法返回一个实例
       System.err.println(instance.getServiceId()+instance.getHost()+instance.getPort());
        //可以查看这个实例的服务名,ip地址,端口号
        return "1";
    }

所以说,默认负载均衡算法是轮询算法。

自定义负载均衡算法

写一个TestConfig类写自定义负载均衡算法,也就是随机算法。

重点:这个TestConfig类必须在启动类的包扫描范围之外,否则会报错

加注解@Configuration标注成配置类

@Configuration
public class TestConfig {
    @Autowired
    IClientConfig iClientConfig;
    /**
     * 创建负载均衡算法的方法
     * @Param config
     */
    @Bean
    public IRule rebbonRule(IClientConfig config){
        return new RandomRule();//返回随机算法
    }
}

然后在启动类上加注解@RibbonClient,指定TestConfig类文件

@RibbonClient(name="PROVIDER-USER",configuration = TestConfig.class) //启用ribbon并对provider-user进行负载均衡

consumer-order-ribbon消费者模块写test方法,如果启动多个提供者模块的服务的话(改一个端口号另外启动),进到eureka页面,点击consumer-order-ribbon服务地址,然后修改为test路径,执行test方法,可以看到后台是随机打印的

这样可以实现不同的服务去使用不同的负载均衡算法。

配置文件配置Ribbon

上面的是在TestConfig配置类中通过注解@Bean组件返回了一个随机算法,并在启动类上加上了注解@RibbonClient启用ribbon并指定TestConfig配置类来进行负载均衡。

除了上面使用class文件配置Ribbon,还可以通过application.yml配置文件配置Ribbon

consumer-order-ribbon消费者模块的配置文件中配置,不配置默认是轮询算法。

PROVIDER-USER:  # 服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 给指定的服务配置负载均衡算法(随机算法)

在配置文件中配置禁用Ribbon

ribbon:
  eureka:
    enabled: false # 在eureka中禁用ribbon,禁用后需要自己负载均衡

Eureka Server的高可用

Eureka Server 的高可用就是通过启动多个 Eureka Server 注册中心,让他们之间进行相互注册,达到共享注册信息的目的。这样就会都持有一份注册信息,即使其中一台挂掉了,其他的 Eureka Server 还在正常工作。

原本只有一个Eureka Server服务注册中心,现在在原来的基础上,把服务注册中心模块的配置文件application.yml删掉

创建配置文件application-peer1.yml

spring:
  application:
    name: eureka-ha
  profiles:
    active: peer1
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
  client:
    service-url:
      defaultZone: http://peer2:8762/eureka/,http://peer3:8763/eureka/

创建配置文件application-peer2.yml

spring:
  application:
    name: eureka-ha
  profiles:
    active: peer2
server:
  port: 8762
eureka:
  instance:
    hostname: peer2
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer3:8763/eureka/

创建配置文件application-peer3.yml

spring:
  application:
    name: eureka-ha
  profiles:
    active: peer3
server:
  port: 8763
eureka:
  instance:
    hostname: peer3
  client:
    service-url:
      defaultZone: http://peer2:8762/eureka/,http://peer1:8763/eureka/

通过spring.profiles.active属性来分别启动peer1和peer2还有peer3(三个Eureka Server服务端)

此时

  • 访问peer1的注册中心localhost:8761,进入eureka页面,可以看到DS Replicas处有了peer2和peer3
  • 访问peer2的注册中心localhost:8762,进入eureka页面,可以看到DS Replicas处有了peer1和peer3
  • 访问peer3的注册中心localhost:8763,进入eureka页面,可以看到DS Replicas处有了peer2和peer1

Feign基本使用

	`Feign`是`Netflix`开发的声明式、模板化的HTTP客户端,` Feign`可以帮助我们更快捷、优雅地调用`HTTP API`。在`Spring Cloud`中,使用`Feign`非常简单——<font color="red">创建一个接口</font>,并在接口上添加一些注解,代码就完成了。`feign`是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似`controller`调用`service`。Spring Cloud集成了`Ribbon`和`Eureka`,可在使用Feign时提供负载均衡的http客户端。

Feign也是在消费者的立场上使用的。

首先拷贝一份consumer-order消费者模块并重命名为consumer-order-feign,在pom文件添加feign的依赖。

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

然后在启动类上添加注解@EnableFeignClients

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ConsumerOrder
{
    public static void main( String[] args )
    {
        SpringApplication.run(ConsumerOrder.class);
    }
}

创建一个接口,@FeignClient("provider-user")注解指定哪个服务

@FeignClient("provider-user")//对应的消费者模块的服务名
public interface Client {

    @RequestMapping(value = {"/user/{id}"})
    User getOrder(@PathVariable("id") Long id);
}

然后把这个接口注入到controller

@RestController
public class OrderController {
    @Autowired
    private Client client;

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Long id){
        User user = client.getOrder(id);
        return user;
    }
}

运行项目,运行顺序(eureka服务端,provider-user提供者,consumer-order-feign消费者)

进入eureka页面,点击consumer-order-feign服务地址,修改链接为/order/1,可以得到user的信息。

Feign自定义配置

在上面接口上面添加的注解@FeignClient("provider-user"),修改为@FeignClient(name = "provider-user",configuration = Client.class),前面指定调用的消费者服务名,后面指定自定义配置文件名Client

新建一个config包,包里新建一个配置类,在这个配置类中对Feign进行配置。

重点:这个Client配置类必须在启动类的包扫描范围之外,否则会报错

@Configuration
public class FeignConfig {
    @Bean
    public Contract feignContract(){
        return new feign.Contract.Default();
    }
}

接口的写法

@FeignClient(name = "provider-user",configuration = Client.class)
public interface Client {
    @RequestLine("GET /user/{id}")  //Feign提供的组合注解,第一个是请求方式,第二个是参数用空格分隔
    User getOrder(@Param("id") Long id);//注意使用@RequestLine注解的时候必须使用@Param注解
}

controller方法

@RestController
public class OrderController {
    @Autowired
    private Client client;

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Long id){
        User user = client.getOrder(id);
        return user;
    }
}

Feign接口调用逻辑

按顺序走?

  1. 启动EurekaServer客户端
  2. 启动一个提供者模块provider-user,该提供者的服务名为provider-user
  3. 启动一个消费者,添加Feign,依赖,启动类注解,上边Feign基本使用有
  4. 在消费者新建一个接口,添加接口注解,接口方法
  5. 在消费者新建一个controller,把(4)的接口注入进来,并进行调用

说明:访问Eureka服务端,进入eureka页面,点击Feign消费者的服务地址,修改路径为/order/1,这个是(5)controller中方法的映射路径,在这个方法中调用(4)接口的方法,然后根据(4)接口的注解@FeignClient@RequestLine指定的提供者的服务名和该服务的路径,然后调用提供者的具体的方法。

Feign的url方式

在上面的接口上的注解是

@FeignClient(name = "provider-user",configuration = Client.class)

可以使用url方式

@FeignClient(url="http://localhost:10000/",configuration = Client.class)

两者效果是相同的。

Feign输出日志

Feign客户端的application.yml文件中加入配置开启日志

logging:
  level: com.qianlong.Feign.Client  # 给指定的Feign Client设置日志输入级别,只有在debug的情况下才会打印日志

在上面自定义配置时指定的配置类中加入日志的配置,配置要输出的日志有哪些,必须在debug模式下才可以输出。

@Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

HyStrix基本使用

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。

举个例子,a服务需要远程调用b服务,b服务需要远程调用c服务,c服务远程调用d基础服务,如果d基础服务发生错误的话,那么c服务会一直连接d服务并且一直连不上,所以服务链上端的a,b服务只能一直等待,最后导致整条服务链不可用,这就是雪崩!讲的够生动了吧?

Hystrix就是解决服务一直在等待导致雪崩的问题,它设置了每个服务去调用下一个服务时等待的时间,如果下一个服务发生错误的话,会到了指定的等待时间之后返回信息,并放弃连接,释放资源。

HyStrix是在消费者的立场的。

首先复制一份消费者模块consumer-order改名为consumer-order-hystrix,并在pom文件加入HyStrix的依赖。

 		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>

然后在启动类上加上注解@EnableCircuitBreaker,表示开启了熔断HyStrix

这个注解@EnableCircuitBreaker的作用,没有这个注解的话,假如c服务调用d服务时,d服务发生错误,c服务会直接执行失败后的回调方法,如果一直重复的发出请求,则会一直重复的请求两次,先是连接服务请求,请求失败后又进行回调;但是加上这个注解后,如果多次请求一个发生错误的服务时,会熔断效果,即不会再去尝试连接服务,而是直接进行失败后的回调方法。

最后回到远程调用提供者服务的controller方法里面,在方法上面加上注解@HystrixCommand(fallbackMethod = "shibai"),该注解表示,优先调用对应的提供者的服务,但是如果发生错误,就比如提供者模块没有启动,接口找不到,那么就会执行fallbackMethod指定的回调方法,这样就不会造成长时间等待连接却连不上的问题。

 @GetMapping("/order/{id}")
    @HystrixCommand(fallbackMethod = "shibai")
    public User getOrder(@PathVariable Long id){
        InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);
        String url= instanceInfo.getHomePageUrl();
        //访问提供者,获取数据
        User user = restTemplate.getForObject(url + "/user/"+id, User.class);//通过访问rest获取到json数据,然后转换为user对象
        return user;
    }
 /**
     * 失败后进行的回调
     * @param id
     * @return
     */
    public User shibai(Long id){
        User user=new User();
        user.setId(-100L);
        user.setDate(new Date());
        return user;
    }

进行测试,启动服务,启动顺序(Eureka服务端,消费者【consumer-order-hystrix】)没有提供者,进入Eureka页面,点击消费者地址,修改路径为order/1,会返回

{"id":-100,"date":1568444848987}

Feign使用HyStrix的fallback

回忆:Feign是在消费者中使用接口远程调用提供者的接口,在接口中使用HyStrixfallback回调。

复制一份consumer-order-feign模块改名为consumer-order-feign-hystrix,添加hystrix依赖。

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>

在yml配置文件中开启FeignHyStrix

feign:
  hystrix:
    enabled: true

然后就可以调用了。

zuul的介绍

在现在为止所有的微服务都是通过 Eureka 找到的,但是在很多的开发之中为了规范微服务的使用,提供有一个路由的处理控制组件:Zuul,也就是说 Zuul 就作为中间的一个代理层出现。

img

客户端想要请求到服务,首先请求到zuul网关,然后zuul网管将请求分发到对应的服务去。

zuul的基本使用

新建一个模块apigateway-zuul,加入依赖

<!--不添加的话,zuul的路由页面无法访问-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>

启动类上加上注解@EnableZuulProxy ,注意一点,这里启动类的run方法中需要加上args。

@SpringBootApplication
@EnableZuulProxy    //启用zuul,自带熔断和自动注册到eureka
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class,args);
    }
}

然后写配置文件

server:
  port: 10900 #程序启动后的端口
spring:
  application:
    name: apigateway-zuul #应用名称,别名
eureka:
  client:
    service-url:
      defaultZone:  http://user:123@localhost:10000/eureka
  instance:
    prefer-ip-address: true # 显示ip
# 配置访问zuul的routes(路由)的时候使用,不加也可以,但是麻烦,账号和密码会随机打印在控制台
security: 
  user:
    name: user
    password: abc

zuul是可以自动注册到eureka中的,启动项目,启动顺序(eurekaServer,提供者,apigateway-zuul),进入eureka页面,点击apigateway-zuul地址

修改路径为http://192.168.0.103:10900/提供者服务的名字(provider-user)/user/1

正常执行提供者中的user/1映射的方法。

zuul自定义服务映射地址

上面路径是http://192.168.0.103:10900/provider-user/user/1,provider-user是服务名,现在给指定服务做映射。

再配置文件中配置

zuul:
  routes: # 配置路由映射
    provider-user: /abc/** #给指定的服务做映射,比如当前是给provider-user添加映射地址为abc

那么启动项目之后,点击apigateway-zuul地址,访问路径就可以修改为

http://192.168.0.103:10900/abc/user/1

zuul取消代理某服务

zuul会从eureka上找到所有的注册的服务,然后全部做代理,如果我们不想要它代理其中一些服务,只需要添加这个配置即可,如果是多个服务,以逗号分隔。

zuul:
  routes: # 配置路由映射
    provider-user: /abc/** #给指定的服务做映射,比如当前是给provider-user添加映射地址为abc
  ignored-services: consumer-order # zuul会从eureka上找到所有的注册的服务,然后全部做代理,如果我们不想要它代理其中一些服务,只需要添加这个配置即可,如果是多个服务,以逗号分隔

访问http://192.168.0.103:10900/routes可以查看zuul代理的所有的服务。

zuul的path映射

给配置文件中加入配置

zuul:
  routes: # 配置路由映射
   abcdef:  # 随便写,但是要保证是唯一的
     path: /abcd/** # 映射的路径
     serviceId: provider-user # 给那个服务做映射,这几行配置相当于前面的那一行配置

zuul的url方式映射

上面是path映射,下面说url映射,如果把path改成url映射的话,熔断和负载均衡将不再支持,因此需要在配置文件中配置ribbon负载均衡。

zuul:
  routes: # 配置路由映射
   abcdef:  # 随便写,但是要保证是唯一的
     path: /abcd/** # 映射的路径
     serviceId: provider-user # 给那个服务做映射,这几行配置相当于前面的那一行配置
ribbon:
  eureka:
    enabled: false # 在eureka中禁用ribbon的负载均衡
provider-user: # 给上面的serviceId对应的服务的名字指定一个ribbon的负载均衡,是从listOfServers配置的地址中选择
  ribbon:
    listOfServers: http://192.168.3.234:7900/,http://192.168.3.234:7901/

zuul的前缀url映射

zuul:
  prefix: /suibian

zuul过滤器

@Component
public class MyPreZuulFilter extends ZuulFilter {
    /**
     * 类型包含 pre post route error
     * pre代表在路由代理之前执行
     * route代表代理的时候执行
     * error代表出现错的时候执行
     * post代表在route或者是error执行完成后执行
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * filter是一个链式调用,一个filter会调用下一个filter,如何知道顺序
     * javaEE中是根据filter的配置先后顺序来决定
     * zull是根据order决定,越小的越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否使用这个过滤器
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return false;
    }

    @Override
    public Object run() {
        System.out.println("过滤器执行了");
        return null;
    }
}

springCloud Config Server介绍

springCloud Config Server,统一配置中心,如果微服务架构中没有使用统一配置中心时,所存在的问题:

  • 配置文件分散在各个项目里,不方便维护
  • 配置内容安全与权限,实际开发中,开发人员是不知道线上环境的配置的
  • 更新配置后,项目需要重启

在SpringCloud中我们使用config组件来作为统一配置中心。
在这里插入图片描述

Config Server的基本使用

加上Config Server依赖

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>

在启动类上面加上注解@EnableConfigServer

在配置文件中加入配置

server:
  port: 12900 #程序启动后的端口
spring: # 配置 配置文件的仓库地址
  cloud:
    config:
      server:
        git:
          uri: https://github.com/jackson/spring-cloud-config

前提是在github中存了一份配置文件,并把配置文件的路径写在uri里,这样项目就可以远程拿到并且使用配置文件中的内容了。

学习就到这里,springcloud只学习的话只是了解了什么是微服务和基本的使用,并不没有独立搭建微服务框架的能力,还是需要在工作中慢慢领悟,并一直学习总结才可以,一起努力吧兄弟盟!

posted @ 2020-03-08 17:12  你樊不樊  阅读(340)  评论(1编辑  收藏  举报