Spring Cloud 入门

我也是菜鸟, 刚刚入坑, 如有错误还请批评指教, 不要打我^^
本博客基于spring boot 2.0.5.RELEASE 版本

Eureka

Euraka用来实现服务的注册与发现, 基于Netfix Eureka做了二次封装
注册中心实现
核心依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

代码

@SpringBootApplication
@EnableEurekaServer  //核心注解
public class EurekaApplication {
	public static void main(String[] args) {
		SpringApplication.run(EurekaApplication.class, args);
	}
}

配置文件

eureka:
  instance:
    hostname: localhost
#  client:
#    service-url:
#      defaultZone: http://localhost:8768/eureka		#多个eureka实现高可用, 相互注册, defaultZone 可接受多个链接, 用逗号间隔
    register-with-eureka: false    		#不会被eureka本身注册
    fetch-registry: false					
  server:
    enable-self-preservation: false    #表示在此eureka服务器中关闭自我保护模式,所谓自我保护模式是指,出现网络分区、eureka在短时间内丢失过多客户端时,会进入自我保护模式,即一个服务长时间没有发送心跳,eureka也不会将其删除。默认为true
server:
  port: 8768
spring:
  application:
    name: euraka

客户端:
核心依赖:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

代码

@SpringBootApplication
@EnableDiscoveryClient    //核心注解
public class ClientApplication {
	public static void main(String[] args) {
		SpringApplication.run(ClientApplication.class, args);
	}
}

配置

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8768/eureka/     #通过url向对应开放的服务端进行注册

数据库

核心依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>     // 工具类
	<scope>provided</scope>
</dependency>

dao层接口

 //集成jpa ProductInfo 封装类,  String 主键类型
public interface ProductInfoReposity extends JpaRepository<ProductInfo, String> {  
	//findBy** jpa自带的书写方式, 另行百度详细查看
    List<ProductInfo> findByProductStatus (Integer productStatus);    

    @Query(value = "select a.* from product_info a where a.product_id in ?1 and a.product_status = 0",nativeQuery=true)
    List<ProductInfo> findByProductId (List<String> productIdList);
}
封装类常用注解
@Data   //  lombok提供的注解   自动生成get set方法
@Entity  //类上   表示数据库封装类
@Id    //属性上   表示该字段位主键
@generatedvalue  //主键生成策略
@Table(name="表名")  //可添加表名前缀
@JsonProperty("name")   //api响应数据名与封装类属性名不同时, 可使用

配置数据源

spring:
  application:
    name: XXX    #应用名称
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: mysql
    url: jdbc:mysql://localhost:3306/spring_cloud?characterEncoding=utf-8&useSSL=false
  jpa:
    show-sql: true

应用通信

可以使用RestTemplate 进行服务间数据交互
方式1

RestTemplate restTemplate = new RestTemplate();      //创建对象
restTemplate.getForObject("服务的url", "返回值类型")    //集群下不可用

方式2

@Autowired
private LoadBalancerClient loadBalancerClient;

ServiceInstance service = loadBalancerClient.choose("服务名");         //通过服务名称获的任意一个服务实例对象
String url = String.format("http://%s:%s", service.getHost(), service.getPort(), "");    //获取服务的url
restTemplate.getForObject(url, "返回值类型")    //请求获取结果

方式3

@Component
public class RestTemplateConfig {
	@Bean
	@LoadBalanced                   // 基于某种规则实现负载均衡, 默认为轮询
	public RestTemplate restTemplate() {
		return new RestTemplate();                    //使用注解方式,  获取restTemplate对象
	}
}

//应用
@Autowired
private RestTemplate restTemplate;

restTemplate.getForObject(url, "返回值类型")    //请求获取结果

客户端负载均衡器 Ribben , 默认为轮询, 可通过配置更改

应用名称:
	ribben:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule     //随机规则

使用feign完成应用间通信(伪RPC)
main方法上打 @EnableFeignClients 注解

依赖

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

接口代码

@FeignClient(name = "product")       //  填写应用名称  spring.application.name
public interface Product {
    @PostMapping("/product/listOrder")    //填写访问的映射
    public ResultVo<List<ProductInfo>> listOrder(@RequestBody List<String> list);     // 方法名可随意指定  返回值 与 api 返回值相同, 参数与 api 接受请求参数相同
}

 @Autowired
private Product product;  //注入接口类

product.listOrder(集合);     //直接调用接口方法即可

统一配置中心

服务端配置
核心依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>                         //配置中心依赖
	<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>                      //自动更新配置依赖
	<artifactId>spring-cloud-starter-bus-amqp</artifactId>
	<version>2.0.0.RELEASE</version>
</dependency>

代码

@SpringBootApplication
@EnableDiscoveryClient           //注册服务
@EnableConfigServer			// 配置中心核心注解
public class ConfigApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConfigApplication.class, args);
	}
}

配置

spring:
  cloud:
      server:
        git:
          uri: https://github.com/XXX/springcloud/      //github  库地址
          username: XXX				//用户名
          password: XXX				//密码
          basedir: D:/workplace/ideawork/springcloud/config/basedir/    // 本地拉下来的配置文件路径
  application:
    name: CONFIG				//应用名称
  rabbitmq:						// mq配置, 通过mq使应用不重启, 自动刷新配置信息
    host: 192.168.99.100
    port: 5672
    username: root
    password: 123456
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8768/eureka/ 				//服务注册地址
server:
  port: 9002				//端口号
management:
  endpoints:
    web:
      exposure:
        include: '*'			//暴露所有bus api 接口
  cloudfoundry:
    enabled: false				// 

命名规则

/{name}-{profiles}.yml
/{label}/{name}-{profiles}.yml

name  应用名称
label  分支名称  branch
profiles  环境名称
例如:
	order-dev.yml    //生产环境配置
	order-test.yml	// 测试环境配置
	order.yml	    //默认读取,  建议存放共用配置 
	若访问出现空白error页面, 说明文件的数据格式有问题,  配置中心无法正常转换格式

客户端使用
核心依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-config-client</artifactId>
</dependency>

更改配置文件名称 application.yml -> bootstrap.yml
需要自动更新的类上打 @RefreshScope 注解
配置文件

spring:
  application:
    name: product		//应用名称
  rabbitmq:				//mq地址
    host: 192.168.99.100
    port: 5672
    username: root
    password: 123456
  cloud:
    config:
      discovery:
        enabled: true				//使用配置
        service-id: CONFIG				//配置服务名称
      profile: dev					//环境,  就是上面的profiles  ,  -后面加的那个东东
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8768/eureka/				// 注册服务
server:
  port: 8081				//端口

通过访问 http://localhost:9002/actuator/bus-refresh 即可手动刷新配置
通过配置github上的webhook实现自动刷新, 不过实现的时候出现了问题, 没能成功, 有大神成功了, 请评论一下, 不胜感激, 问题请详看 待解决

MQ的使用

普通方式调用mq 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>				//使用普通mq方式
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

代码:

// 发送端
@Autowired
private AmqpTemplate amqpTemplate;     //注入模板

  amqpTemplate.convertAndSend("myQueue", "now:" + new Date());				// mq普通调用

 amqpTemplate.convertAndSend("myExchange", "boy" , "now:" + new Date());				// mq分组调用
 amqpTemplate.convertAndSend("myExchange", "girl" , "now:" + new Date());					// mq分组调用
//接收端
@Slf4j
@Component
public class MqReceiver {

   @RabbitListener(queuesToDeclare = @Queue("myQueue"))       //普通mq,  自动创建mq
    public void process(Object message) {
        log.info("mqReceiver : {}", message);
    }

    @RabbitListener(bindings = @QueueBinding(				//分组方式,  通过key 路由不同的mq
            exchange = @Exchange("myExchange"),				//mq 组名称
            key = "boy",					// 通过key 区分不同的mq
            value = @Queue("boyQueue")				//mq名称
    ))
    public void processGroup1(Object message) {
        log.info("boyQueue : {}", message);
    }

    @RabbitListener(bindings = @QueueBinding(         		 //分组方式,  通过key 路由不同的mq
            exchange = @Exchange("myExchange"),
            key = "girl",				// 通过key 区分不同的mq
            value = @Queue("girlQueue")					//mq名称
    ))
    public void processGroup2(Object message) {
        log.info("girlQueue : {}", message);
    }
}

配置见上文, 配置mq信息就可以了

使用 Stream 方式调用 mq 依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>				// 使用stream 方式
	<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

代码

//发送端
@Autowired
private StreamClient streamClient;

streamClient.input().send(MessageBuilder.withPayload("hahahah").build());

// 接口
public interface StreamClient {

    String INPUT = "input";					//  mq的名称
    String OUTPUT = "output";

    @Input(INPUT)				// 暂时不明白,   我的理解是通常call的mq地址
    SubscribableChannel input();

    @Output(OUTPUT)				// 暂时不明白,  我的理解是转发的mq地址, 
    MessageChannel output();
}

//接收端
@Component
@Slf4j
@EnableBinding(StreamClient.class)
public class StreamReceiver {

    @StreamListener(StreamClient.INPUT)				//监听mq
    @SendTo(StreamClient.OUTPUT)				//转发到其他mq,  返回结果信息
    public Object process(Object message) {
        log.info("Stream input receive: {}",  message);
        return "ok";
    }

    @StreamListener(StreamClient.OUTPUT)
    public void process2(String message) {
        log.info("Stream output receive: {}", message);
    }

}

分组mq使用场景, 当服务调用mq 对应多个不同的服务时
例如: 订单服务 -> mq -> (电器类(mq) -> 电器类服务, 文具类(mq) -> 文具类服务, 水果类(mq) -> 水果类服务)

网关

zuul 依赖

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

核心注解 @EnableZuulProxy

配置:

zuul:
  routes:
    # 可随意明明
    a:
      path: /myproduct/**      #自定义路由路径
      seviceId: product		#目标服务路径
      sensitiveHeaders:      #敏感头的过滤
    #简洁写法
    # product: /myproduct/**
  # 不被网关管理的路径
  ignored-patterns:
    - /product/env/print		#网关会忽略改路径的路由
    - /myproduct/env/print
  #  prefix:    统一前缀

若要实现动态配置, 需注册到eureka, 并且关联到配置中心, application.xml -> bootstrap.xml

zuul可以做校验, 限权, 限流等功能, 下面是限流的简单实现

@Component
public class RateLimitFilter extends ZuulFilter {
	//  谷歌的限流工具类
    private static final RateLimiter rateLimiter = RateLimiter.create(100);
	/**
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
    @Override
    public String filterType() {
        return PRE_TYPE;			
    }

    @Override
    public int filterOrder() {
        return SERVLET_DETECTION_FILTER_ORDER - 1;          //过滤器的执行顺序,  数值越小越优先
    }
	
	//  a "true" return from this method means that the run() method should be invoked
	// 可以放在配置中进行动态更新
    @Override
    public boolean shouldFilter() {
        return true;
    }
	
	//  this method is the core method of a ZuulFilter
    @Override
    public Object run() throws ZuulException {
        if (!rateLimiter.tryAcquire()) {
            throw new RateLimitException();
        }
        return null;
    }
}

跨域问题

  1. 在被调用的方法或类上, 添加@CrossOrigin 注解
  2. 在zuul中添加 CorsFilter过滤器
@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);    //是否允许cookie 跨域
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setMaxAge(300L);
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

}

Spring Cloud Hsytrix

可以实现服务降级, 熔断

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
```@RestController
@RequestMapping("productOrder")
@DefaultProperties(defaultFallback = "defaultFallback")   // 服务降级默认配置
public class ProductOrderController {

    @HystrixCommand(
    	// fallbackMethod="fallback",    // 自定义服务降级方法
    	commandProperties = {
    		@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="3000"),   // 超时配置
            @HystrixProperty(name="circuitBreaker.enabled", value="true"),    //开启熔断设置
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold", value="10"),   //  number of requests that must be made within a statisticalWindow before open/close decisions are made using stats
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds", value="10000"),   // 熔断时间
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage", value="60")  // 超过60% 请求失败, 将会进入熔断状态
    })
    @GetMapping("hello")
    public String getProductList(){
        RestTemplate restTemplate = new RestTemplate();
        String hello = restTemplate.getForObject("http://localhost:8081/env/hello", String.class);
        return hello;
    }
   // 服务降级自定义方法
    public String fallback() {
        return "hystric feedback";
    }
    // 服务降级默认方法
    public String defaultFallback() {
        return "default hystrix fallback";
    }

}

可通过配置方式对参数进行配置, 添加 @HystrixCommand 注解

hystrix:
  command:
    default:    //默认配置
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
    getProductList:    // 默认根据方法名进行配置,  可修改注解中 commandKey进行更改
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 1000

feign 方式

开启配置

feign:
  hystrix:
    enabled: true
	
	@FeignClient(name = "product", fallback = ProductFallback.class)      //注解上设置fallback 的 回调类
	
@Component
public class ProductFallback implements  Product {
    @Override
    public ResultVo<List<ProductInfo>> listOrder(@RequestBody List<String> list) {
        return null;     // 写fallback的行为
    }
}

Hystrix Dashboard

依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

核心注解 @EnableHystrixDashboard
配置:

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

访问路径: http://localhost:8890/hystrix
在这里插入图片描述

参考: https://www.jianshu.com/p/4ad8acb15380

问题

1 向eureka注册的客户端启动后自动关闭
加入依赖

<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
</dependency>

待解决

通过配置github上的webhook实现自动刷新, host为内网穿透生成的, 通过XXX/actuator/bus-refresh可以刷新 ,但是webhook不行, 错误404
在这里插入图片描述
回调结果
在这里插入图片描述

{"timestamp":"2018-10-11T16:53:51.083+0000","status":404,"error":"Not Found","message":"No message available","path":"/monitor"}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值