Spring Cloud 2天速学学习记录

基础知识补充

对象复制

	    Product product = productService.findById(id);
        Product result = new Product();
        BeanUtils.copyProperties(product,result);

线程睡眠

        TimeUnit.SECONDS.sleep(1);

Spring Boot使用Redis

  • 依赖

            org.springframework.boot
            spring-boot-starter-data-redis
        
  • 配置文件(Spring下)
redis:
	    database: 0
	    host: 127.0.0.1
	    port: 6379
	    timeout: 2000
  • 日志打印
private final Logger logger = LoggerFactory.getLogger(getClass);
logger.info("test");

项目使用参见熔断一章

创建Eureka时idea勾选依赖。

创建消费者时idea勾选依赖。

消费者Ribbon

创建Ribbon时idea勾选依赖。

  • web > web
  • clouding discovery > eureka discovery
  • clouding routing > ribbon

启动类加入

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

调用方法一(Map可以接受Json数据)

	Map<String,Object> productMap = restTemplate.getForObject("http://product-service/api/v1/product/find?id="+productId, Map.class);

调用方法二

    @Autowired
    private LoadBalancerClient loadBalancer;
    
    ServiceInstance instance = loadBalancer.choose("product-service");
    String url = String.format("http://%s:%s/api/v1/product/find?id="+productId, instance.getHost(),instance.getPort());
    RestTemplate restTemplate = new RestTemplate();
    Map<String,Object> productMap = restTemplate.getForObject(url, Map.class);

自定义负载均衡

product-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

消费者feign

依赖

 		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
	    </dependency>

启动类添加

	@EnableFeignClients

增加一个接口

	@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);
}

调用

 	@Autowired
 	private ProductClient productClient;
	String response = productClient.findById(productId);

修改超时调用

feign:
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000

feign包含ribben。自定义负载均衡同上

Hystrix熔断

使用方法一

  • 加入依赖

           
              org.springframework.cloud
              spring-cloud-starter-netflix-hystrix
          
    
  • 启动类加入注解

@EnableCircuitBreaker
  • 方法里加入注解
@RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", productOrderService.save(userId, productId));
        return  data;
    }


    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){

        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }

方法二 Feign开启hystrix

  • 配置文件
feign:
  hystrix:
    enabled: true
  • Client上加这个方法,自定义一个返回类
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
  • 代码例子
/**
 * 针对商品服务,错降级处理
 */
@Component
public class ProductClientFallback implements ProductClient {
    @Override
    public String findById(int id) {

        System.out.println("feign 调用product-service findbyid 异常");

        return null;
    }
}

熔断降级项目报警

  • 使用Redis注解
    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
    拿取key-value类型值
    **/
    String sendValue = redisTemplate.opsForValue().get(saveOrderKye);
  • 代码示例
//监控报警
        String saveOrderKye = "save-order";

        String sendValue = redisTemplate.opsForValue().get(saveOrderKye);
        final String ip = request.getRemoteAddr();
        new Thread( ()->{
            if (StringUtils.isBlank(sendValue)) {
                System.out.println("紧急短信,用户下单失败,请离开查找原因,ip地址是="+ip);
                //发送一个http请求,调用短信服务 TODO
                redisTemplate.opsForValue().set(saveOrderKye, "save-order-fail", 20, TimeUnit.SECONDS);

            }else{
                System.out.println("已经发送过短信,20秒内不重复发送");
            }

        }).start();


        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;

熔断超时时间处理

	hystrix:
	  command:
	    default:
	      execution:
	        isolation:
	          thread:
	            timeoutInMilliseconds: 4000

断路器Dashboard监控仪表盘实战

  • 加入依赖
       
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix-dashboard
        

        
            org.springframework.boot
            spring-boot-starter-actuator
        
  • 启动类增加注解
@EnableHystrixDashboard
  • 配置文件增加endpoint
management:
  endpoints:
    web:
      exposure:
        include: "*"
  • 4、访问入口
    http://localhost:8781/hystrix

    Hystrix Dashboard输入: http://localhost:8781/actuator/hystrix.stream

微服务网关zuul

  • 创建勾选依赖
    Cloud Discovery 》 Eureka Discovery
    Cloud Routing 》 Zuul
  • 启动类加入注解
	@EnableZuulProxy

默认访问规则
http://gateway:port/service-id/**

			例子:默认 /order-service/api/v1/order/save?user_id=2&product_id=1
				 自定义 /xdclass_order/api/v1/order/save?user_id=2&product_id=1

	自定义路由转发:
		zuul:
		 routes:
		 	order-service: /apigateway/**


	环境隔离配置:
		需求 :不想让默认的服务对外暴露接口
			/order-service/api/v1/order/save

		配置:
		zuul: 
			ignored-patterns:
				- /*-service/api/v1/order/save

Zuul常用问题分析

1、路由名称定义问题
	路由映射重复覆盖问题

2、Http请求头过滤问题

3、过滤器执行顺序问题 ,过滤器的order值越小,越先执行


4、共享RequestContext,上下文对象

自定义Zuul过滤器实现登录鉴权实战

简介:自定义Zuul过滤器实现登录鉴权实战

1、新建一个filter包

2、新建一个类,实现ZuulFilter,重写里面的方法

3、在类顶部加注解,@Component,让Spring扫描
package net.xdclass.apigateway.filter;


import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * 登录过滤器
 */
@Component
public class LoginFilter  extends ZuulFilter {

    /**
     * 过滤器类型,前置过滤器
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 过滤器顺序,越小越先执行
     * @return
     */
    @Override
    public int filterOrder() {

        return 4;
    }


    /**
     * 过滤器是否生效
     * @return
     */
    @Override
    public boolean shouldFilter() {

        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest  request = requestContext.getRequest();

       //System.out.println(request.getRequestURI()); ///apigateway/product/api/v1/product/list
        //System.out.println(request.getRequestURL()); //http://localhost:9000/apigateway/product/api/v1/product/list

        //ACL

        if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
            return true;
        }else if ("/apigateway/order/api/v1/order/list".equalsIgnoreCase(request.getRequestURI())){
            return true;
        }else if ("/apigateway/order/api/v1/order/find".equalsIgnoreCase(request.getRequestURI())){
            return true;
        }

        return false;
    }

    /**
     * 业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {

        //JWT
        RequestContext requestContext =  RequestContext.getCurrentContext();
        HttpServletRequest  request = requestContext.getRequest();

        //token对象
        String token = request.getHeader("token");

        if(StringUtils.isBlank((token))){
            token  = request.getParameter("token");
        }


        //登录校验逻辑  根据公司情况自定义 JWT
        if (StringUtils.isBlank(token)) {
                requestContext.setSendZuulResponse(false);
                requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

谷歌guava限流

package net.xdclass.apigateway.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * 订单限流
 */
@Component
public class OrderRateLimiterFilter extends ZuulFilter {


    //每秒产生1000个令牌
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -4;
    }



    @Override
    public boolean shouldFilter() {


        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        //只对订单接口限流
        if ("/apigateway/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
            return true;
        }

        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        if(!RATE_LIMITER.tryAcquire()){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }



}

待学内容

  • 兰布达表达式
  • 如何配置线程池

你可能感兴趣的:(编程记录)