springcloud入门之网关服务

springcloud通过zuul来实现路由网关服务的,路由网关是整个springcloud项目的门户所在,他能提供一个统一的入口供客户端访问,他涉及到的的服务模块众多,他在远程服务调用中担当服务消费者的角色,客户端的请求到达网关,网关会代理到别的服务上,由别的服务模块完成相应的功能。

在springcloud入门这个系列项目中,springcloud接收两个请求,一个是保存用户信息,即save(name),他会调用feign服务提供的save(name)方法,另一个请求是获取一个message,即get()方法,他会调用ribbon服务提供的get()方法。

网关项目gateway需要通过feign和ribbon的方式调用远程服务,因此他需要依赖spring-cloud-starter-openfeign和spring-cloud-starter-netflix-ribbon,他还需要实现熔断策略,因此还需要依赖spring-cloud-starter-netflix-hystrix,作为网关他需要依赖spring-cloud-starter-netflix-zuul,他也需要作为eureka client注册到服务注册中心,因此需要依赖spring-cloud-starter-netflix-eureka-client。

gateway项目依赖配置:


	org.springframework.cloud
	spring-cloud-starter
	2.0.1.RELEASE


	org.springframework.cloud
	spring-cloud-starter-netflix-eureka-client
	2.0.1.RELEASE


	org.springframework.cloud
	spring-cloud-starter-netflix-zuul
	2.0.1.RELEASE


	org.springframework.cloud
	spring-cloud-starter-netflix-hystrix
	2.0.1.RELEASE


	org.springframework.cloud
	spring-cloud-starter-netflix-ribbon
	2.0.1.RELEASE


	org.springframework.cloud
	spring-cloud-starter-openfeign
	2.0.1.RELEASE


	org.webjars
	jquery
	3.3.1

依赖中加入jquery,是为了在前端页面中使用jquery,这里网关项目提供网关,也提供UI。

为了操作用户,我们定义User实体,和前面feign项目中用到的User实体是一样的。

package com.xxx.gateway.domain;

import java.util.Date;

public class User {
    private Integer id;
    private String name;
    private String mobile;
    private Date birth;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }
    public User(){}
    public User(String name){
        this.name = name;
        this.mobile = "";
        this.birth = new Date();
    }
}

这里只是控制层操作User,因此无需指定表名、主键,也无需生成构造方法,使用默认构造方法。

这里重点是service层的几个类和方法:

首先是RibbonService.java

package com.xxx.gateway.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class RibbonService {
    @Autowired
    private RestTemplate restTemplate;
    @HystrixCommand(fallbackMethod = "fallbackGet")
    public String get(){
        return  restTemplate.getForObject("http://ribbon/get",String.class);
    }


    public String fallbackGet(){
        return "hystrix service broker.";
    }
}

这里就涉及到了ribbon远程服务调用的方式,我们需要一个RestTemplate实例对象,然后需要指定服务地址。这里get()方法也通过hystrix熔断服务指定了当远程服务调用失败的时候,备用方法是fallbackGet()。这里需要注入的RestTemplate对象,我们通过如下方式配置:

package com.xxx.gateway.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }
}

另外一个服务类FeignService.java

package com.xxx.gateway.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.xxx.gateway.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class FeignService {
    @Autowired
    private UserService userService;

    @HystrixCommand(fallbackMethod = "fallbackSave")
    public List save(String name){
        return userService.save(name);
    }

    public List fallbackSave(String name){
        List list = new ArrayList<>();
        User user = new User("user service broker.");
        list.add(user);
        return list;
    }
}

它也通过hystrix熔断机制,指定了调用远程方法失败时候的备选方法fallbackSave(String name),这里备选方法也需要带上和主方法一样的参数。另外这里UserService就是我们通过feign远程调用服务的方式来调用feign项目提供的服务的。

package com.xxx.gateway.service;

import com.xxx.gateway.domain.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
@FeignClient("feign")
public interface UserService {

    @RequestMapping(method= RequestMethod.POST, value = "/save",
       produces = MediaType.APPLICATION_JSON_VALUE,
       consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public List save(@RequestBody String name);
}

UserService是一个接口,只需要通过@FeignClient("feign")注解就可以实现远程服务调用,并且调用时需要通过@RequestMapping()来指定请求的方法。 

 控制层的方法就很简单了,直接调用服务层service里对应的类和方法,是一个很普通的controller。

package com.xxx.gateway.controller;
import com.xxx.gateway.domain.User;
import com.xxx.gateway.service.FeignService;
import com.xxx.gateway.service.RibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class WebController {
    @Autowired
    private RibbonService ribbonService;
    @Autowired
    private FeignService feignService;

    @RequestMapping(value = "/dispatch")
    @ResponseBody
    public List sendMessage(@RequestBody String name){
        return feignService.save(name);
    }

    @RequestMapping(value = "/get",produces = {MediaType.TEXT_PLAIN_VALUE})
    public String get(){
        return ribbonService.get();
    }
}

启动类:

package com.xxx.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

@EnableEurekaClient表示开启eureka client的支持,@EnableCircuitBreaker表示开启熔断机制,@EnableFeignClients表示开启feign远程调用客户端支持,@EnableZuulProxy表示开始网关路由支持。

最后,到了配置文件出场的时候了,也是application.yml

server:
  port: 80

和bootstrap.yml 

spring:
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    non-secure-port: ${server.port:80}

另外我们在resources路径下建立一个static文件夹,存放静态页面文件,里面就一个index.html,项目启动直接就可以访问到。内容如下:




    
    gateway
    
    
    


hello,springcloud

启动gateway项目,没有报错,那么启动成功。可以在服务发现管理页面看到gateway服务也加入了进来:

springcloud入门之网关服务_第1张图片 我们按照服务暴露的访问地址访问index.html页面。

springcloud入门之网关服务_第2张图片

点击get message按钮,第一次可能会显示ribbon service broker,第二次显示了正确的信息:

springcloud入门之网关服务_第3张图片

在第一个输入框中输入beijing,点击save按钮,返回结果显示user service broker。其实已经存入成功,只不过返回了备选方法的结果。 

springcloud入门之网关服务_第4张图片

我们再次输入shanghai,点击save按钮,页面上显示了所有用户名:

springcloud入门之网关服务_第5张图片

这个示例很好的展示了springcloud作为微服务框架给我们带来的体验。 gateway只是一个客户端请求统一入口,真正干活的是feign服务和ribbon服务。到这里一个最简单的springcloud示例就展示了,最后还有一个monitor服务,如果看代码不明白,可以看看springcloud入门系列的其他项目:

springcloud入门之服务发现

springcloud入门之配置服务

springcloud入门之通过feign实现负载均衡

springcloud入门之通过ribbon实现负载均衡

项目源代码:https://github.com/buejee/springcloud

你可能感兴趣的:(java)