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项目依赖配置:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>3.3.1</version>
</dependency>

依赖中加入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<User> save(String name){
        return userService.save(name);
    }

    public List<User> fallbackSave(String name){
        List<User> 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<User> 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<User> 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,项目启动直接就可以访问到。内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>gateway</title>
    <style type="text/css">
        .box{border:1px solid #ddd;border-radius:2px;padding:10px;}
    </style>
    <script type="text/javascript" src="/webjars/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn-save").click(function () {
                $.ajax({
                    url:'/dispatch',
                    type:'POST',
                    data:$("#name").val(),
                    dataType:'json',
                    headers:{'Content-Type':"application/json"},
                    success:function(data){
                        console.log(data);
                        data = data.map(function(item,i){
                           return item.name;
                        });
                        $("#user-list").html(data.join("|"));
                    }
                });
            });
            $("#btn-get").click(function () {
                $.ajax({
                    url:'/get',
                    type:'GET',
                    success:function(data){
                        $("#messagelist").html(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
<h2>hello,springcloud</h2>
<div id="container">
    <div class="box">
        <label>username</label>
        <input type="text" name="name" id="name"/>
        <input type="button" id="btn-save" value="save"/>
        <div id="user-list"></div>
    </div>
    <div class="box">
        <input type="button" id="btn-get" value="get message"/>
        <div id="messagelist"></div>
    </div>
</div>
</body>
</html>

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

 我们按照服务暴露的访问地址访问index.html页面。

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

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

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

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

springcloud入门之服务发现

springcloud入门之配置服务

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值