Spring cloud学习总结

Stella981
• 阅读 603

1 注册中心学习

  maven配置

<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-eureka-server</artifactId>
        </dependency>

2 配置

spring.application.name=spring-cloud-eureka

server.port=8000
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/

 3 访问地址:

http://localhost:8000/

 4 eclipse也有自动装配的 spring cloud项目了

Spring cloud学习总结

3 okhttp3 的使用可以替代 apache 的httpclient,很好用,两个例子

get和post的方法

应该是spring cloud封装了okhttp3 依赖是

io.github.openfeign
feign-okhttp


org.springframework.cloud
spring-cloud-openfeign-core
2.0.0.M1
provided

原生的依赖是:

com.squareup.okhttp3 okhttp 4.0.1 这个是最新版的

下面是两个例子
@Test
public void testGet(){
//创建OkHttpClient实例对象
OkHttpClient okHttpClient = new OkHttpClient();
//创建Request对象
Request request = new Request.Builder()
.url("https://www.httpbin.org/get?id=111")
.addHeader("key","value")
.get()
.build();
//执行Request请求
//异步请求
/*okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//请求失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求成功
Log.d("TestOkHttp",response.body().string());
}
});*/
//同步请求
try {
Response response = okHttpClient.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void testPost(){
//1、创建OkHttpClient对象实例
OkHttpClient okHttpClient = new OkHttpClient();
//2、创建Request对象
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(mediaType,"{}");
Request request = new Request.Builder()
.url("https://www.httpbin.org/post")
.post(requestBody)
.build();
//3、执行Request请求
try {
Response response = okHttpClient.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}

 4  okhttp3 的自己的拦截器,请求前设置设置token等值。。。如果返回时过期的则重新刷新后再次重新生成

import com.github.wxiaoqi.security.auth.client.config.ServiceAuthConfig;
import com.github.wxiaoqi.security.auth.client.config.UserAuthConfig;
import com.github.wxiaoqi.security.auth.client.jwt.ServiceAuthUtil;
import com.github.wxiaoqi.security.common.constant.CommonConstants;
import com.github.wxiaoqi.security.common.context.BaseContextHandler;
import lombok.extern.java.Log;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
* @author ace
*/
@Component
@Log
public class OkHttpTokenInterceptor implements Interceptor {
@Autowired
@Lazy
private ServiceAuthUtil serviceAuthUtil;
@Autowired
@Lazy
private ServiceAuthConfig serviceAuthConfig;
@Autowired
@Lazy
private UserAuthConfig userAuthConfig;

@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = null;
if (chain.request().url().toString().contains("client/token")) {
newRequest = chain.request()
.newBuilder()
.header(userAuthConfig.getTokenHeader(), BaseContextHandler.getToken())
.build();
} else {
newRequest = chain.request()
.newBuilder()
.header(userAuthConfig.getTokenHeader(), BaseContextHandler.getToken())
.header(serviceAuthConfig.getTokenHeader(), serviceAuthUtil.getClientToken())
.build();
}
Response response = chain.proceed(newRequest);
if (HttpStatus.FORBIDDEN.value() == response.code()) {
if (response.body().string().contains(String.valueOf(CommonConstants.EX_CLIENT_INVALID_CODE))) {
log.info("Client Token Expire,Retry to request...");
serviceAuthUtil.refreshClientToken();
newRequest = chain.request()
.newBuilder()
.header(userAuthConfig.getTokenHeader(), BaseContextHandler.getToken())
.header(serviceAuthConfig.getTokenHeader(), serviceAuthUtil.getClientToken())
.build();
response = chain.proceed(newRequest);
}
}
return response;
}
}

保存修改成功

5 使用 feign 做的 请求负载均衡

使用了接口和服务名
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;


import java.util.List;

/**
* Created by ace on 2017/9/15.
*/
@FeignClient(value = "${auth.serviceId}",configuration = {})
public interface ServiceAuthFeign {
@RequestMapping(value = "/client/myClient")
public ObjectRestResponse<List> getAllowedClient(@RequestParam("serviceId") String serviceId, @RequestParam("secret") String secret);
@RequestMapping(value = "/client/token",method = RequestMethod.POST)
public ObjectRestResponse getAccessToken(@RequestParam("clientId") String clientId, @RequestParam("secret") String secret);
@RequestMapping(value = "/client/servicePubKey",method = RequestMethod.POST)
public ObjectRestResponse<byte[]> getServicePublicKey(@RequestParam("clientId") String clientId, @RequestParam("secret") String secret);
@RequestMapping(value = "/client/userPubKey",method = RequestMethod.POST)
public ObjectRestResponse<byte[]> getUserPublicKey(@RequestParam("clientId") String clientId, @RequestParam("secret") String secret);

}

6 spring 配置拦截器的第二种方式,用类继承的

import com.github.wxiaoqi.security.auth.client.annotation.IgnoreClientToken;
import com.github.wxiaoqi.security.auth.client.config.ServiceAuthConfig;
import com.github.wxiaoqi.security.auth.client.jwt.ServiceAuthUtil;
import com.github.wxiaoqi.security.auth.common.util.jwt.IJWTInfo;
import com.github.wxiaoqi.security.common.exception.auth.ClientForbiddenException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
* Created by ace on 2017/9/12.
*/
@SuppressWarnings("ALL")
public class ServiceAuthRestInterceptor extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(ServiceAuthRestInterceptor.class);

@Autowired
private ServiceAuthUtil serviceAuthUtil;

@Autowired
private ServiceAuthConfig serviceAuthConfig;

private List allowedClient;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 配置该注解,说明不进行服务拦截
IgnoreClientToken annotation = handlerMethod.getBeanType().getAnnotation(IgnoreClientToken.class);
if (annotation == null) {
annotation = handlerMethod.getMethodAnnotation(IgnoreClientToken.class);
}
if(annotation!=null) {
return super.preHandle(request, response, handler);
}

String token = request.getHeader(serviceAuthConfig.getTokenHeader());
IJWTInfo infoFromToken = serviceAuthUtil.getInfoFromToken(token);
String uniqueName = infoFromToken.getUniqueName();
for(String client:serviceAuthUtil.getAllowedClient()){
if(client.equals(uniqueName)){
return super.preHandle(request, response, handler);
}
}
throw new ClientForbiddenException("Client is Forbidden!");
}
}

7 配置全局异常的方法@ControllerAdvice

import com.github.wxiaoqi.security.common.constant.CommonConstants;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.exception.auth.ClientTokenException;
import com.github.wxiaoqi.security.common.exception.auth.UserInvalidException;
import com.github.wxiaoqi.security.common.exception.auth.UserTokenException;
import com.github.wxiaoqi.security.common.msg.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;

/**
* Created by ace on 2017/9/8.
*/
@ControllerAdvice("com.github.wxiaoqi.security")
@ResponseBody
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(ClientTokenException.class)
public BaseResponse clientTokenExceptionHandler(HttpServletResponse response, ClientTokenException ex) {
response.setStatus(403);
logger.error(ex.getMessage(),ex);
return new BaseResponse(ex.getStatus(), ex.getMessage());
}

@ExceptionHandler(UserTokenException.class)
public BaseResponse userTokenExceptionHandler(HttpServletResponse response, UserTokenException ex) {
response.setStatus(200);
logger.error(ex.getMessage(),ex);
return new BaseResponse(ex.getStatus(), ex.getMessage());
}

@ExceptionHandler(UserInvalidException.class)
public BaseResponse userInvalidExceptionHandler(HttpServletResponse response, UserInvalidException ex) {
response.setStatus(200);
logger.error(ex.getMessage(),ex);
return new BaseResponse(ex.getStatus(), ex.getMessage());
}

@ExceptionHandler(BaseException.class)
public BaseResponse baseExceptionHandler(HttpServletResponse response, BaseException ex) {
logger.error(ex.getMessage(),ex);
response.setStatus(500);
return new BaseResponse(ex.getStatus(), ex.getMessage());
}

@ExceptionHandler(Exception.class)
public BaseResponse otherExceptionHandler(HttpServletResponse response, Exception ex) {
response.setStatus(500);
logger.error(ex.getMessage(),ex);
return new BaseResponse(CommonConstants.EX_OTHER_CODE, ex.getMessage());
}

}

8 获取客户ip的真实ip的三种方法

public class ClientUtil {
/**
* 获取客户端真实ip
* @param request
* @return
*/
public static String getClientIp(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if (ip==null||ip.length()==0||"unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip==null||ip.length()==0||"unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip==null||ip.length()==0||"unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}

9  反射强制直线set get 设置值,获取值,忽略 private protected 的修饰符,

package com.github.wxiaoqi.security.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
* 反射工具类.
* 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
* @author calvin
* @version 2013-01-15
*/
@SuppressWarnings("rawtypes")
public class ReflectionUtils {

private static final String SETTER_PREFIX = "set";

private static final String GETTER_PREFIX = "get";

private static final String CGLIB_CLASS_SEPARATOR = "$$";

private static Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);

/**
* 调用Getter方法.
* 支持多级,如:对象名.对象名.方法
*/
public static Object invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
return object;
}

/**
* 调用Setter方法, 仅匹配方法名。
* 支持多级,如:对象名.对象名.方法
*/
public static void invokeSetter(Object obj, String propertyName, Object value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}else{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}

/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);

if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}

Object result = null;
try {
result = field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}

/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);

if (field == null) {
logger.error("Could not find field [" + fieldName + "] on target [" + obj + "]");
return;
//throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
try {
field.set(obj, convert(value, field.getType()));
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常:{}", e.getMessage());
}
}

public static Object convert(Object object, Class<?> type) {
if (object instanceof Number) {
Number number = (Number) object;
if (type.equals(byte.class) || type.equals(Byte.class)) {
return number.byteValue();
}
if (type.equals(short.class) || type.equals(Short.class)) {
return number.shortValue();
}
if (type.equals(int.class) || type.equals(Integer.class)) {
return number.intValue();
}
if (type.equals(long.class) || type.equals(Long.class)) {
return number.longValue();
}
if (type.equals(float.class) || type.equals(Float.class)) {
return number.floatValue();
}
if (type.equals(double.class) || type.equals(Double.class)) {
return number.doubleValue();
}
}
if(type.equals(String.class)){
return object==null?"":object.toString();
}
return object;
}

/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型,
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}

try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}

/**
* 直接调用对象方法, 无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
}

try {
return method.invoke(obj, args);
} catch (Exception e) {
throw convertReflectionExceptionToUnchecked(e);
}
}

/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
*
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}

/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型。
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");

for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}

/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名。
*
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
Validate.notNull(obj, "object can't be null");
Validate.notBlank(methodName, "methodName can't be blank");

for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
makeAccessible(method);
return method;
}
}
}
return null;
}

/**
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}

/**
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}

/**
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
* 如无法找到, 返回Object.class.
* eg.
* public UserDao extends HibernateDao
*
* @param clazz The class to introspect
* @return the first generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("unchecked")
public static Class getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}

/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*
* 如public UserDao extends HibernateDao<User,Long>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or Object.class if cannot be determined
*/
public static Class getClassGenricType(final Class clazz, final int index) {

Type genType = clazz.getGenericSuperclass();

if (!(genType instanceof ParameterizedType)) {
logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}

Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

if (index >= params.length || index < 0) {
logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}

return (Class) params[index];
}

public static Class getUserClass(Object instance) { Assert.notNull(instance, "Instance must not be null"); Class clazz = instance.getClass(); if (clazz != null && clazz.getName().contains(CGLIB\_CLASS\_SEPARATOR)) { Class superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;

}

/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(((InvocationTargetException) e).getTargetException());
} else if (e instanceof RuntimeException) {
return (RuntimeException) e;
}
return new RuntimeException("Unexpected Checked Exception.", e);
}
/**
* 判断某个对象是否拥有某个属性
*
* @param obj 对象
* @param fieldName 属性名
* @return 有属性返回true
* 无属性返回false
*/
public static boolean hasField(final Object obj, final String fieldName){
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
return false;
}
return true;

}
}

3 sleuth跟踪器

1 spring cloud sleuth 服务跟踪系统
使用具体流程,server, 调用trace1 会调用trace2,搭建这三个,
开始配置跟踪,1 先在trace1和2添加 sleuth的 maven依赖
2 请求返回四个字段【a,b,c,d】 a表示 trace1名字,b表示tracieid 一个链路一个 id,c表示 spanid,就是每个小段的id,d是truefalse,
默认false,表示sleuth不收集数据

 2 跟踪器需要和 zipkin整合

zipkin是 推特开源的  分布式链路系统,优点是有个好看的ui界面,包括了server名字等等

要改 的话如果不整合 spring boot,只需要两步

1 添加 java包,第二 配置端口和server name ,第三是启动 enablezipkin, 然后浏览器浏览器就可以看到主界面了

 Spring cloud学习总结

localhost:port/ 就是首页\

3 Zuul的学习

参考 文档https://www.cnblogs.com/ityouknow/p/6944096.html
1 Zuul 
添加网关为了统一来处理 请求接口
1 添加依赖 引入 spring-cloud-starter-zuul
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
2 属性文件, 请求 /it/xxx直接跳转到 ityoukneowxxx,类似于代理
spring.application.name=gateway-service-zuul
server.port=8888

#这里的配置表示,访问/it/** 直接重定向到http://www.ityouknow.com/**
zuul.routes.baidu.path=/it/**
zuul.routes.baidu.url=http://www.ityouknow.com/

3 启动类 这样请求会自动重定向
@SpringBootApplication
@EnableZuulProxy
public class GatewayServiceZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayServiceZuulApplication.class, args);
    }
}
4 更高级的如果新添加了,或者动态不指定 路径则无法实现了,后来
思路是 用服务会euroke
1 添加 euroke
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2 修改属性
spring.application.name=gateway-service-zuul
server.port=8888

zuul.routes.api-a.path=/producer/**
zuul.routes.api-a.serviceId=spring-cloud-producer

eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
如果配置了集群,则会自动 负载均衡,在请求转发的情况下,这样就转发到了集群

nginx和 zuul功能差不多

4 Hystrix

1 hystrix
随意实施的熔断对整个系统的影响是灾难性的
雪崩效应
一个错导致级联错误,所以需要  熔断,像保险丝一样
 错误产生于调用服务端,所以只在客户端加熔断就可以了
 1 属性文件加上
 feign.hystrix.enabled=true
 2 建立回调类
 @Component
public class HelloRemoteHystrix implements HelloRemote{

    @Override
    public String hello(@RequestParam(value = "name") String name) {
        return "hello" +name+", this messge send failed ";
    }
}

3 添加调用错误的回调 fallback
@FeignClient(name= "spring-cloud-producer",fallback = HelloRemoteHystrix.class)
public interface HelloRemote {

    @RequestMapping(value = "/hello")
    public String hello(@RequestParam(value = "name") String name);

}
4 测试步骤是启动服务和客户端,调用正常,关闭服务端,调用仍然返回数据的
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这