zoukankan      html  css  js  c++  java
  • Spring cloud学习总结

    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项目了

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

    get和post的方法

    应该是spring cloud封装了okhttp3 依赖是
    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-openfeign-core</artifactId>
    <version>2.0.0.M1</version>
    <scope>provided</scope>
    </dependency>

    原生的依赖是:
    <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
    <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.0.1</version>
    </dependency>
    这个是最新版的

    下面是两个例子
    @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<String>> 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<String> 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<User>
    *
    * @param clazz The class to introspect
    * @return the first generic declaration, or Object.class if cannot be determined
    */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> 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, 然后浏览器浏览器就可以看到主界面了

     

    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 测试步骤是启动服务和客户端,调用正常,关闭服务端,调用仍然返回数据的
  • 相关阅读:
    sublime text3在指定浏览器上本地服务器(localhost)运行文件(php)
    关于Content-Type的问题
    为什么开发要用一个大的背景图
    2017-04-17
    我的第一篇博客
    b站计算机网络谢希仁6网络层续3
    b站计算机网络谢希仁6网络层续2
    b站计算机网络谢希仁6网络层续1
    b站操作系统2.10互斥
    b站操作系统2.9并发
  • 原文地址:https://www.cnblogs.com/genestart/p/11211026.html
Copyright © 2011-2022 走看看