【spring cloud】微信点餐系统 springcloud 学习笔记

概要:基于netflix的springcloud搭建微信点餐系统

第一部分 项目概要

1、项目环境信息

项目环境信息
IDEA  ultimate 2017.2.5Docker 17.12.0-ce
springboot 2.0.0.M3Rancher 2.0
springCloud Finchley.M2 

 

2、介绍

基于netflix eureka做了二次封装

两个组件组成:

  - Eureka Server 注册中心

  - Eureka Client 服务注册

 

第二部分 搭建Eureka Server

1、配置Eureka 的application.yml


  
  
  1. eureka:
  2. client:
  3. serviceUrl:
  4. defaultZone: http://localhost:8761/eureka/
  5. register-with-eureka: false #默认为true,是否向自己注册自己
  6. server:
  7. enable-self-preservation: false #显示客户端连接状态
  8. spring:
  9. application:
  10. name: spring-cloud-eureka
  11. server:
  12. port: 8761

 

2、配置Eureka pom.xml

-- 由于廖师兄的版本采用默认的,无法完成注册

springboot 版本采用 1.5.10.RELEASE

SpringCloud版本采用Edgware.SR2


 
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0 </modelVersion>
  5. <groupId>com.smileLsf </groupId>
  6. <artifactId>eureka </artifactId>
  7. <version>0.0.1-SNAPSHOT </version>
  8. <packaging>jar </packaging>
  9. <name>eureka </name>
  10. <description>Demo project for Spring Boot </description>
  11. <parent>
  12. <groupId>org.springframework.boot </groupId>
  13. <artifactId>spring-boot-starter-parent </artifactId>
  14. <version>1.5.10.RELEASE </version>
  15. <relativePath/> <!-- lookup parent from repository -->
  16. </parent>
  17. <properties>
  18. <project.build.sourceEncoding>UTF-8 </project.build.sourceEncoding>
  19. <project.reporting.outputEncoding>UTF-8 </project.reporting.outputEncoding>
  20. <java.version>1.8 </java.version>
  21. <spring-cloud.version>Edgware.SR2 </spring-cloud.version>
  22. </properties>
  23. <dependencies>
  24. <dependency>
  25. <groupId>org.springframework.cloud </groupId>
  26. <artifactId>spring-cloud-starter-eureka-server </artifactId>
  27. <version>1.4.3.RELEASE </version>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot </groupId>
  31. <artifactId>spring-boot-starter-test </artifactId>
  32. <scope>test </scope>
  33. </dependency>
  34. </dependencies>
  35. <dependencyManagement>
  36. <dependencies>
  37. <dependency>
  38. <groupId>org.springframework.cloud </groupId>
  39. <artifactId>spring-cloud-dependencies </artifactId>
  40. <version>${spring-cloud.version} </version>
  41. <type>pom </type>
  42. <scope>import </scope>
  43. </dependency>
  44. </dependencies>
  45. </dependencyManagement>
  46. <build>
  47. <plugins>
  48. <plugin>
  49. <groupId>org.springframework.boot </groupId>
  50. <artifactId>spring-boot-maven-plugin </artifactId>
  51. </plugin>
  52. </plugins>
  53. </build>
  54. <repositories>
  55. <repository>
  56. <id>spring-milestones </id>
  57. <name>Spring Milestones </name>
  58. <url>https://repo.spring.io/milestone </url>
  59. <snapshots>
  60. <enabled>false </enabled>
  61. </snapshots>
  62. </repository>
  63. </repositories>
  64. </project>

3、Eureka 入口类

-- 添加EnableEurekaServer注解


  
  
  1. @EnableEurekaServer
  2. @SpringBootApplication
  3. public class EurekaApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(EurekaApplication.class, args);
  6. }
  7. }

4、Eureka的高可用

设置启动端口在VM options设置启动端口

-Dserver.port=8761

 启动多个可以如下配置,相互注册,截取廖师兄的图一用

 

第三部分 客户端注册发现

1、客户端入口类

-- 添加EnableDiscoveryClient,提供eureka客户端


  
  
  1. @EnableDiscoveryClient
  2. @SpringBootApplication
  3. public class ProductApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(ProductApplication.class, args);
  6. }
  7. }

2、Client新建application.yml


 
 
  1. eureka:
  2. client:
  3. serviceUrl:
  4. defaultZone: http://localhost:8761/eureka/
  5. # instance:
  6. # hostname: product #页面跳转后台端口前名称
  7. spring:
  8. application:
  9. name: product
  10. datasource:
  11. driver-class-name: com.mysql.jdbc.Driver
  12. username: root
  13. password: 123456
  14. url: jdbc:mysql://127.0.0.1:3306/springcloud_sell?characterEncoding=utf-8&useSSL= false
  15. jpa:
  16. show-sql: true
  17. env:
  18. dev

3、Client新建pom.xml


 
 
  1. <parent>
  2. <groupId>org.springframework.boot </groupId>
  3. <artifactId>spring-boot-starter-parent </artifactId>
  4. <version>1.5.10.RELEASE </version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <properties>
  8. <project.build.sourceEncoding>UTF-8 </project.build.sourceEncoding>
  9. <project.reporting.outputEncoding>UTF-8 </project.reporting.outputEncoding>
  10. <java.version>1.8 </java.version>
  11. <spring-cloud.version>Edgware.SR2 </spring-cloud.version>
  12. <product-common.version>0.0.1-SNAPSHOT </product-common.version>
  13. </properties>
  14. <dependencyManagement>
  15. <dependencies>
  16. <dependency>
  17. <groupId>org.springframework.cloud </groupId>
  18. <artifactId>spring-cloud-dependencies </artifactId>
  19. <version>${spring-cloud.version} </version>
  20. <type>pom </type>
  21. <scope>import </scope>
  22. </dependency>
  23. <dependency>
  24. <groupId>com.smilelsf </groupId>
  25. <artifactId>product-common </artifactId>
  26. <version>${product-common.version} </version>
  27. </dependency>
  28. </dependencies>
  29. </dependencyManagement>

4、客户端书写中间实体(*)


  
  
  1. @Data
  2. public class ProductVO {
  3. /**
  4. * 此处需要返回给前端name,但是表示的是类目名称,所以添加JsonProperty进行标识
  5. */
  6. @JsonProperty("name")
  7. private String categoryName;
  8. @JsonProperty("type")
  9. private Integer categoryType;
  10. @JsonProperty("foods")
  11. List <ProductInfoVO> productInfoVOList;
  12. }

5、商品的更新字段的处理

  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间 -- 修改时自动更新',


  
  
  1. @Data
  2. @Entity
  3. @DynamicUpdate
  4. public class ProductInfo {}

商品实体添加@DynamicUpdate注解

 

第四部分 Ribbon实现负载均衡,对比RestTemplate和Feign的使用

1、了解ribbon

Eureka属于客户端发现,客户端会向服务器拉取可用的服务器信息,根据负载均衡服务,命中那台服务器发送请求,整个过程都是在客户端完成,并不需要服务器的参与。

 

Ribbon是netflix ribbon实现的,通过springcloud的封装,轻松的面向服务的rest的模板请求,自动的转换为客户端服务调用。

RestTemplate/zuul/Feign都使用到了ribbon

 

SpringCloud在结合ribbon的负载均衡实践中,封装增加了HTTPClient和OKHttpClient 两种请求端实现,默认使用了ribbon对eureka的客户端发现的负载均衡client

2、ribbon的工作原理

轮寻RoundRobinRule、随机连接RandomRule

 

ribbon实现软负载均衡核心有三点

(1)服务发现:依据实例名称,把该实例下所有的实例都找出来

(2)服务选择规则:依据规则从多个规则中选择有效的服务

(3)服务监听:检测失效的服务,做到高效剔除

 

ribbon主要组件

serverList (获取所有的可用服务列表)----> ServerListFilter(过滤掉一部分地址) -----> IRule从剩下的地址中选择一个实例,作为目标结果

 

3、RestTemplate 操作和Feign简单对比

a、RestTemplate 操作

详解restTemplate操作  https://blog.csdn.net/itguangit/article/details/78825505

方式一:直接使用restTemplate,路径固定了不好修改

restTemplate对于路径的访问比较固定,如果线上部署,不好进行修改;或者是启动了多个实例,不好进行捕获和调用


  
  
  1. RestTemplate restTemplate = new RestTemplate();
  2. String response = restTemplate.getForObject("http://localhost:9001/msg", String.class);
  3. log.info("response{}",response);
  4. return response;

方式二:利用LoadBalancerClient通过应用名获取url,然后在使用restTemplate

注入LoaderBalancerClient,通过服务名称进行获取服务的ip和端口号


 
 
  1. @Autowired
  2. private LoadBalancerClient loadBalancerClient;
  3. @GetMapping( "/getProductMsg")
  4. public String getProductMsg(){
  5. // 方式二:(利用LoadBalancerClient通过应用名获取url,然后在使用restTemplate)
  6. RestTemplate restTemplate = new RestTemplate();
  7. ServiceInstance serviceInstance = loadBalancerClient.choose( "PRODUCT");
  8. String url = String.format( "http://%s:%s", serviceInstance.getHost(),serviceInstance.getPort() + "/msg");
  9. String response = restTemplate.getForObject(url, String.class);
  10. log.info( "response{}",response);
  11. return response;
  12. }

 方式三:通过LoadBalanced实例化restTemplate


 
 
  1. @Component
  2. public class RestTemplateConfig {
  3. @Bean
  4. @LoadBalanced
  5. public RestTemplate restTemplate() {
  6. return new RestTemplate();
  7. }
  8. }

通过模块名称进行访问,随机分配一个服务 

String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);

 
 

 

b、Feign进行通信

  • 声明式Rest客户端(伪RPC)
  • 采用了基于接口的注解

第一步:引入pom.xml依赖


  
  
  1. <!--应用间通信-->
  2. <dependency>
  3. <groupId>org.springframework.cloud </groupId>
  4. <artifactId>spring-cloud-starter-feign </artifactId>
  5. </dependency>

第二步:添加EnableFeignClient注解

第三步:通过@FeignClient声明被调用的服务信息


 
 
  1. @FeignClient(value = "product", fallback = ProductClientFallbackImpl.class )
  2. public interface ProductClient {
  3. /**
  4. * 获取产品端的信息
  5. *
  6. * @return
  7. */
  8. @GetMapping( "/msg")
  9. String getProductMsg();
  10. }

通过fallback处理异常等信息


 
 
  1. @Component
  2. @Slf4j
  3. public class ProductClientFallbackImpl implements ProductClient {
  4. /**
  5. * 获取产品端的信息
  6. *
  7. * @return
  8. */
  9. @Override
  10. public String getProductMsg() {
  11. log.info( "返回消息接口出现问题");
  12. return null;
  13. }
  14. }

第五部分 config配置中心

 

1、Config服务引入pom.xml


  
  
  1. <dependency>
  2. <groupId>org.springframework.cloud </groupId>
  3. <artifactId>spring-cloud-config-server </artifactId>
  4. </dependency>

2、Config服务配置yml文件


  
  
  1. eureka:
  2. client:
  3. serviceUrl:
  4. defaultZone: http://localhost:8761/eureka/
  5. spring:
  6. application:
  7. name: config
  8. cloud:
  9. config:
  10. server:
  11. git:
  12. uri: https://gitee.com/SmileLsf/springCloud_configRepo
  13. username: 用户名
  14. password: 密码
  15. basedir: /IDEAWorkSpace/springcloud_sell_v2/config/basedir

3、Config启动类上引入ConfigServer注解


 
 
  1. @SpringBootApplication
  2. @EnableEurekaClient
  3. @EnableConfigServer
  4. public class ConfigApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(ConfigApplication.class, args);
  7. }
  8. }

4、order客户端pom.xml


  
  
  1. <!--config配置中心-->
  2. <dependency>
  3. <groupId>org.springframework.cloud </groupId>
  4. <artifactId>spring-cloud-config-client </artifactId>
  5. </dependency>

bootstrap.yml中配置


  
  
  1. spring:
  2. application:
  3. name: order
  4. cloud:
  5. config:
  6. discovery:
  7. enabled: true
  8. service-id: CONFIG #配置中心的服务名称
  9. profile: dev

配置完成之后通过

localhost:8989/order-dev.yml进行访问

通过localhost:8989/bus/refresh 进行动态刷新本地的配置信息

配置中心出现的问题:

a、springcloud 消息总线读取配置文件的两种方式

      https://blog.csdn.net/qq_35275233/article/details/89074886

b、springcloud监控配置中心健康状态

https://blog.csdn.net/qq_35275233/article/details/89074380

c、SpringCloud 配置中心执行bus/refresh 出现 Full authentication is required to access this resource

https://blog.csdn.net/qq_35275233/article/details/89074294

六 通过rabbitmq给各服务发送消息

1、发送消息


 
 
  1. /**
  2. * 测试给家电和水果服务发送消息
  3. */
  4. @Test
  5. public void sendOrderMqMsg() {
  6. amqpTemplate.convertAndSend( "myOrder", "computer", "now:" + new Date());
  7. }

 2、设置消息监听


 
 
  1. /**
  2. * 1/测试给家电服务发送消息
  3. * @param message
  4. */
  5. @RabbitListener(bindings = @QueueBinding(
  6. exchange = @Exchange( "myOrder"),
  7. key = "computer",
  8. value = @Queue( "computerOrder")
  9. ))
  10. public void processComputer (String message) {
  11. log.info( "ComputerOrder:{}",message);
  12. }
  13. /**
  14. * 2/测试给水果服务发送消息
  15. * @param message
  16. */
  17. @RabbitListener(bindings = @QueueBinding(
  18. exchange = @Exchange( "myOrder"),
  19. key = "fruit",
  20. value = @Queue( "fruitOrder")
  21. ))
  22. public void processFruit (String message) {
  23. log.info( "FruitOrder:{}",message);
  24. }

七 SpringCloud Stream

官方定义stream为微服务应用构建消息驱动能力的框架,为springcloud的另一个组件

目前springcloud支持的消息中间件是RabbitMQ和Kafka

 1、引入pom.xml


 
 
  1. <dependency>
  2. <groupId>org.springframework.cloud </groupId>
  3. <artifactId>spring-cloud-starter-stream-rabbit </artifactId>
  4. </dependency>

2、待补充

 

八 服务网关和Zuul

路由 + 过滤器 = zuul

除了springbus外,zuul也可以实现自动刷新配置

 
 
  1. /**
  2. * 实现配置的动态注入
  3. */
  4. @Component
  5. public class ZuulConfig {
  6. @ConfigurationProperties( "zuul")
  7. @RefreshScope
  8. public ZuulProperties zuulProperties() {
  9. return new ZuulProperties();
  10. }
  11. }

 

a、pre和post过滤器

1、访问前进行参数校验

pre-filter:请求到目标结果之前,对返回的结果进行加工,访问连接中需要添加token,进行接口加密校验

 
 
  1. @Component
  2. public class TokenFilter extends ZuulFilter {
  3. @Override
  4. public String filterType() {
  5. return PRE_TYPE;
  6. }
  7. @Override
  8. public int filterOrder() {
  9. return PRE_DECORATION_FILTER_ORDER - 1;
  10. }
  11. @Override
  12. public boolean shouldFilter() {
  13. return true;
  14. }
  15. @Override
  16. public Object run() {
  17. RequestContext requestContext = RequestContext.getCurrentContext();
  18. HttpServletRequest request = requestContext.getRequest();
  19. String token = request.getParameter( "token");
  20. if (StringUtils.isEmpty(token)) {
  21. requestContext.setSendZuulResponse( false);
  22. requestContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
  23. }
  24. return null;
  25. }
  26. }

2、post-fileter : 请求到目标结果之后,对返回的结果进行加工


 
 
  1. @Component
  2. public class AddResponseHeaderFilter extends ZuulFilter {
  3. @Override
  4. public String filterType() {
  5. return POST_TYPE;
  6. }
  7. @Override
  8. public int filterOrder() {
  9. return SEND_RESPONSE_FILTER_ORDER - 1;
  10. }
  11. @Override
  12. public boolean shouldFilter() {
  13. return true;
  14. }
  15. @Override
  16. public Object run() {
  17. /**
  18. * 往返回的结果添加x-foo
  19. */
  20. RequestContext requestContext = RequestContext.getCurrentContext();
  21. HttpServletResponse response = requestContext.getResponse();
  22. response.setHeader( "X-FOO", UUID.randomUUID().toString());
  23. return null;
  24. }
  25. }

 

b、Zuul 限流

时机:请求被转发之前调用

令牌桶:拿到令牌的放行

限流过滤器


 
 
  1. /**
  2. * 限流过滤器
  3. */
  4. @Component
  5. public class RateLimitFilter extends ZuulFilter {
  6. /**
  7. * guava的令牌桶算法:放入100个令牌
  8. */
  9. private static final RateLimiter RATE_LIMITER = RateLimiter.create( 100);
  10. @Override
  11. public String filterType() {
  12. return PRE_TYPE;
  13. }
  14. @Override
  15. public int filterOrder() {
  16. return SERVLET_DETECTION_FILTER_ORDER - 1;
  17. }
  18. @Override
  19. public boolean shouldFilter() {
  20. return true;
  21. }
  22. @Override
  23. public Object run() {
  24. /**
  25. * tryAcquire(1, 0, TimeUnit.MICROSECONDS);
  26. * 取到一个令牌
  27. */
  28. if (!RATE_LIMITER.tryAcquire()) {
  29. throw new RateLimitException();
  30. }
  31. return null;
  32. }
  33. }

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值