五、Spring Cloud - Netflix(Zuul服务网关构建代码层面)

五、Spring Cloud - Netflix(Zuul服务网关构建代码层面)

本文依然是基于http://blog.didispace.com/springcloud5/博主提供的部分代码,以及大部分的使用思路。大笑

1)项目的结构(5个都要用到,不单单2017-Netflix_Zuul哦得意


2)看代码

pom.xml

<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>com.sample</groupId>
	<artifactId>2017-Netflix_Zuul</artifactId>
	<version>1.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	
	<build>  
	    <plugins>  
	        <plugin>  
	            <groupId>org.apache.maven.plugins</groupId>  
	            <artifactId>maven-compiler-plugin</artifactId>  
	            <version>3.3</version>  
	            <configuration>  
	                <!-- 指定source和target的版本 -->                 
	                <source>1.8</source>  
	                <target>1.8</target>  
	            </configuration>  
	        </plugin>  
	    </plugins>  
	</build> 
	
	<parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>1.5.2.RELEASE</version>
	</parent>
	<dependencyManagement>
	    <dependencies>
	        <dependency>
	            <groupId>org.springframework.cloud</groupId>
	            <artifactId>spring-cloud-dependencies</artifactId>
	            <version>Dalston.RELEASE</version>
	            <type>pom</type>
	            <scope>import</scope>
	        </dependency>
	    </dependencies>
	</dependencyManagement>
	<dependencies>
	    <dependency>
	        <groupId>org.springframework.cloud</groupId>
	        <artifactId>spring-cloud-starter-config</artifactId>
	    </dependency>
	    <dependency>
	        <groupId>org.springframework.cloud</groupId>
	        <artifactId>spring-cloud-starter-eureka</artifactId>
	    </dependency>
<!-- 		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-starter-hystrix</artifactId>
		</dependency>		    
		<dependency>
			<groupId>com.netflix.hystrix</groupId>
			<artifactId>hystrix-javanica</artifactId>
		</dependency> 		 -->
		<dependency>
		    <groupId>org.springframework.cloud</groupId>
		    <artifactId>spring-cloud-starter-zuul</artifactId>
		</dependency>		
	</dependencies>	
	
</project>
application.properties
spring.application.name=api-gateway
server.port=5555

# 启动2017-Netflix_ServiceA和2017-Netflix_ServiceB, 它们两提供不同的两个服务
# routes to url (第一种 url映射方式)
zuul.routes.api-a-url.path=/api-a-url/**
zuul.routes.api-a-url.url=http://localhost:8091/

# routes to serviceId (第二种 serviceId映射方式)
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=netflix-service-a

zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=netflix-service-b

# 用于验证zuul自带的负载均衡功能, 启动2017-Netflix_Service1和2017-Netflix_Service2, 它们两提供同一个服务netflix-service
zuul.routes.api-service.path=/api-service/**
zuul.routes.api-service.serviceId=netflix-service

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

# Zuul测试连接如下
#http://localhost:5555/api-a-url/add?a=1&b=2
#http://localhost:5555/api-a/add?a=1&b=2
#http://localhost:5555/api-service/add?a=1&b=2

# 下面其实还是走原有Ribbon, 已经测试过了
#http://localhost:5555/zuulRibbonCallAddService

zuul.routes.customers=/customers/**
package com.jack.ssm.fallback;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;

/**
 * ClassName:GenericZuulFallbackProvider.java
 * 
 * http://tachniki.blogspot.in/2017/02/generic-ZuulFallbackProvider.html参考这篇文章
 * 将多个熔断器抽象成一个公共的熔断类,然后在spring boot application里面根据不同的route ID,实现对应的熔断器.
 *  
 * Date:     2017年6月7日下午1:49:35
 * @author   Jack.Huang
 * @version  V1.0
 * @since    JDK 1.7.0_60/JDK 1.8.0_45
 */

public class GenericZuulFallbackProvider implements ZuulFallbackProvider {

	private String responseBody = "{\"message\":\"Service Unavailable. Please try after sometime\"}";
	private HttpHeaders headers = null;
	private String route = null;
	private int rawStatusCode = 503;
	private HttpStatus statusCode = HttpStatus.SERVICE_UNAVAILABLE;
	private String statusText = "Service Unavailable";
	
	@Override
	public String getRoute() {
		if (route == null) 
			route = "route";	//	若为空, 则熔断默认route ID="route", 但我配置文件没配这个这只是一种实现的样例.
		return route;
	}

	/**
	 * 熔断器会调用下面的fallbackResponse方法,最终模拟返回一个ClientHttpResponse.
	 * 里面包含HttpHeaders、rawStatusCode、statusCode和responseBody等信息,这些信息都可以自定义返回值.
	 * MediaType则包含多种返回信息的格式Json、Pdf、Image等等.
	 * 
	 * @see org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider#fallbackResponse()
	 */
	@Override
	public ClientHttpResponse fallbackResponse() {
		return new ClientHttpResponse(){

			@Override
			public InputStream getBody() throws IOException {
				if (responseBody == null) 
					responseBody ="{\"message\":\"Service Unavailable. Please try after sometime\"}";
				return new ByteArrayInputStream(responseBody.getBytes());
			}

			@Override
			public HttpHeaders getHeaders() {
				if (headers == null) { 
					headers = new HttpHeaders();
					headers.setContentType(MediaType.APPLICATION_JSON);
				}
				return headers;
			}

			@Override
			public void close() {
				
			}

			@Override
			public int getRawStatusCode() throws IOException {
				return rawStatusCode;
			}

			@Override
			public HttpStatus getStatusCode() throws IOException {
				if (statusCode == null) 
					statusCode = HttpStatus.SERVICE_UNAVAILABLE;
				return statusCode;
			}

			@Override
			public String getStatusText() throws IOException {
				if (statusText == null)
					statusText = "Service Unavailable";
				return statusText;
			}
			
		};
	}

	public String getResponseBody() {
		return responseBody;
	}

	public void setResponseBody(String responseBody) {
		this.responseBody = responseBody;
	}

	public HttpHeaders getHeaders() {
		return headers;
	}

	public void setHeaders(HttpHeaders headers) {
		this.headers = headers;
	}

	public int getRawStatusCode() {
		return rawStatusCode;
	}

	public void setRawStatusCode(int rawStatusCode) {
		this.rawStatusCode = rawStatusCode;
	}

	public HttpStatus getStatusCode() {
		return statusCode;
	}

	public void setStatusCode(HttpStatus statusCode) {
		this.statusCode = statusCode;
	}

	public String getStatusText() {
		return statusText;
	}

	public void setStatusText(String statusText) {
		this.statusText = statusText;
	}

	public void setRoute(String route) {
		this.route = route;
	}

}
package com.jack.ssm;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate;

import com.jack.ssm.fallback.GenericZuulFallbackProvider;

/**
 * ClassName:RibbonApplication.java 
 * Date:     2017年6月5日下午5:06:00
 * @author   Jack.Huang
 * @version  V1.0
 * @since    JDK 1.7.0_60/JDK 1.8.0_45
 */

@EnableZuulProxy
//@EnableZuulServer
@SpringCloudApplication	//	它整合了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
public class ZuulRibbonApplication {

	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
	
	public static void main(String[] args) {
		SpringApplication.run(ZuulRibbonApplication.class, args);
	}
	
	@Bean
	public ZuulFallbackProvider routeAPIAZuulFallbackProvider() {
		GenericZuulFallbackProvider routeZuulFallback = new GenericZuulFallbackProvider();
		routeZuulFallback.setRoute("netflix-service-a");
		return routeZuulFallback;
	}
	
	@Bean
	public ZuulFallbackProvider routeAPIbZuulFallbackProvider() {
		GenericZuulFallbackProvider routeZuulFallback = new GenericZuulFallbackProvider();
		routeZuulFallback.setRoute("netflix-service-b");
		return routeZuulFallback;
	}
	
	@Bean
	public ZuulFallbackProvider netflixServiceZuulFallbackProvider() {
		GenericZuulFallbackProvider portalZullFallback = new GenericZuulFallbackProvider();
		portalZullFallback.setRoute("netflix-service");
		portalZullFallback.setRawStatusCode(200);
        portalZullFallback.setStatusCode(HttpStatus.OK);
        portalZullFallback.setResponseBody("We are little busy. Comeback After Sometime");
		return portalZullFallback;
	}
	
	/*
	@Bean
	public ZuulFallbackProvider zuulFallbackProvider() {
		return new ZuulFallbackProvider() {
            @Override
            public String getRoute() {
                return "customers";
            }

            @Override
            public ClientHttpResponse fallbackResponse() {
                return new ClientHttpResponse() {
                    @Override
                    public HttpStatus getStatusCode() throws IOException {
                        return HttpStatus.OK;
                    }

                    @Override
                    public int getRawStatusCode() throws IOException {
                        return 200;
                    }

                    @Override
                    public String getStatusText() throws IOException {
                        return "OK";
                    }

                    @Override
                    public void close() {

                    }

                    @Override
                    public InputStream getBody() throws IOException {
                        return new ByteArrayInputStream("fallback".getBytes());
                    }

                    @Override
                    public HttpHeaders getHeaders() {
                        HttpHeaders headers = new HttpHeaders();
                        headers.setContentType(MediaType.APPLICATION_JSON);
                        return headers;
                    }
                };
            }
        };		
	}
	*/
}
3) 验证Zuul路由跳转功能

启动2017-Netflix_Server

java -jar 2017_Netflix_Eureka_Server-1.0.1-SNAPSHOT.jar --spring.profiles.active=eureka

再分别启动2017-Netflix_ServiceA、2017-Netflix_ServiceB以及2017-Netflix_Zuul

他们的启动命令都是这个, spring boot嘛: G:\GIT-WORKPLACE\project\2017-Netflix_Zuul>mvn spring-boot:run


Zuul测试连接如下:
http://localhost:5555/api-a-url/add?a=1&b=2&accessToken=token
http://localhost:5555/api-a/add?a=1&b=2&accessToken=token
http://localhost:5555/api-b-url/add?a=1&b=2&accessToken=token
http://localhost:5555/api-b/add?a=1&b=2&accessToken=token


4) 验证Zuul负载均衡功能

启动2017-Netflix_Server

java -jar 2017_Netflix_Eureka_Server-1.0.1-SNAPSHOT.jar --spring.profiles.active=eureka

再分别启动2017-Netflix_Service1、2017-Netflix_Service1以及2017-Netflix_Zuul


Zuul测试连接如下:

http://localhost:5555/api-service/add?a=1&b=2&accessToken=token

Zuul负载均衡功能默认是实现的,代码不需要写任何东西。


5) 验证Zuul熔断功能

Zuul熔断功能默认也是实现的,但是需要写东西哦。

官网有例子http://cloud.spring.io/spring-cloud-static/Dalston.RELEASE/#hystrix-fallbacks-for-routes,

但是很tm坑啊,按官网的是没效果的,还需要在ZuulRibbonApplication加入如下类似代码。

	@Bean
	public ZuulFallbackProvider routeAPIAZuulFallbackProvider() {
		GenericZuulFallbackProvider routeZuulFallback = new GenericZuulFallbackProvider();
		routeZuulFallback.setRoute("netflix-service-a");
		return routeZuulFallback;
	}
参考歪国友人的文章: 大笑
http://tachniki.blogspot.in/2017/02/generic-ZuulFallbackProvider.html

歪果友人同时也提供了一个公共熔断的实现方案,以及不同服务路由的不同熔断规则的实现方案。


附带源码

https://Git.coding.NET/JackHuang0801/project.git

拉分支release-spring-cloud-1.1



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值