乐趣区

关于java:第五阶段day01

1.Spring Cloud

Spring Cloud 是一个工具集, 集成了多种工具, 来解决微服务中的各种问题
微服务的整体解决方案 微服务全家桶

微服务治理,服务注册和发现 eureka
负载平衡、申请重试 ribbon
断路器,服务降级、熔断 hystrix
ribbon + hystrix 集成,并提供申明式客户端 feign
hystrix 数据监控 hystrix dashboard 和 turbine
API 网关,提供微服务的对立入口,并提供对立的权限验证 zuul
配置核心 config
音讯总线, 配置刷新 bus
链路跟踪 sleuth+zipkin

Spring Cloud 不是一个解决繁多问题的框架!!!

2. 开发环境
IDEA 或 STS
Lombok
Maven

3.Spring Cloud 和 Dubbo 的区别

Dubbo
1.Dubbo 只是一个近程调用 (RPC) 框架
2. 默认基于长连贯, 反对多种序列化格局

Spring Cloud
1. 框架集
2. 提供了一整套微服务解决方案(全家桶)
3. 基于 http 调用, Rest API

4.service- 服务

五.item service 商品服务
1. 新建我的项目
2. 配置依赖 pom.xml 增加 commons 依赖
3. 配置 application.yml

4. 配置主程序
5. 编写代码

业务实现层
@Slf4j
@Service
public class ItemServiceImpl implements ItemService {

@Override
public List<Item> getItems(String orderId) {ArrayList<Item> list = new ArrayList<Item>();
    list.add(new Item(1, "商品 1",1));
    list.add(new Item(2, "商品 2",2));
    list.add(new Item(3, "商品 3",3));
    list.add(new Item(4, "商品 4",4));
    list.add(new Item(5, "商品 5",5));
    return list;
}

@Override
public void decreaseNumbers(List<Item> list) {for(Item item : list) {log.info("缩小库存 -"+item);
    }
}

}
管制层

@Slf4j
@RestController
public class ItemController {

@Autowired
private ItemService itemService;

@Value("${server.port}")
private int port;

@GetMapping("/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {log.info("server.port="+port+", orderId="+orderId);
    
    List<Item> items = itemService.getItems(orderId);
    return JsonResult.ok(items).msg("port="+port);
}

@PostMapping("/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {itemService.decreaseNumbers(items);
    return JsonResult.ok();}

}

Spring MVC 接管参数的几个注解

@RequestParam
1. 表单参数, 键值对参数
2. 能够承受 get 或 post 申请提交的参数
3.name1=value&name2=value2&name3=value3
@PathVariable
1. 申请门路参数
2.http://localhost:8080/123
http://localhost:8080/123/aa/bb
@RequestBody
1.post 申请协定体中的数据
2. 残缺的承受协定中的 json 数据

六.user service 用户服务
1. 新建我的项目
2. 配置依赖 pom.xml
3. 配置 yml 文件

4. 配置主程序
5. 编写代码

业务层

@Slf4j
@Service
public class UserServiceImpl implements UserService {

@Value("${sp.user-service.users}")
private String userJson;

@Override
public User getUser(Integer id) {log.info("users json string :"+userJson);
    List<User> list = JsonUtil.from(userJson, new TypeReference<List<User>>() {});
    for (User u : list) {if (u.getId().equals(id)) {return u;}
    }
    
    return new User(id, "name-"+id, "pwd-"+id);
}

@Override
public void addScore(Integer id, Integer score) {
    // 这里减少积分
    log.info("user"+id+"- 减少积分"+score);
}

}

管制层

@Slf4j
@RestController
public class UserController {


@Autowired
private UserService userService;

@GetMapping("/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId) {log.info("get user, userId="+userId);
    User u = userService.getUser(userId);
    return JsonResult.ok(u);
}

@GetMapping("/{userId}/score") 
public JsonResult addScore(@PathVariable Integer userId, Integer score) {userService.addScore(userId, score);
    return JsonResult.ok();}

}

七. order service 订单服务

  1. 新建我的项目
  2. 配置依赖 pom.xml
  3. 配置 application.yml
  4. 配置主程序
  5. 编写代码

业务层

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

@Override
public Order getOrder(String orderId) {
    //TODO: 调用 user-service 获取用户信息
    //TODO: 调用 item-service 获取商品信息
    Order order = new Order();
    order.setId(orderId);
    return order;
}

@Override
public void addOrder(Order order) {
    //TODO: 调用 item-service 缩小商品库存
    //TODO: 调用 user-service 减少用户积分
    log.info("保留订单:"+order);
}

}

管制层

@Slf4j
@RestController
public class OrderController {

@Autowired
private OrderService orderService;

@GetMapping("/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId) {log.info("get order, id="+orderId);
    
    Order order = orderService.getOrder(orderId);
    return JsonResult.ok(order);
}

@GetMapping("/")
public JsonResult addOrder() {
    // 模仿 post 提交的数据
    Order order = new Order();
    order.setId("123abc");
    order.setUser(new User(7,null,null));
    order.setItems(Arrays.asList(new Item[] {new Item(1,"aaa",2),
            new Item(2,"bbb",1),
            new Item(3,"ccc",3),
            new Item(4,"ddd",1),
            new Item(5,"eee",5),
    }));
    orderService.addOrder(order);
    return JsonResult.ok();}

}

八 eureka 注册与发现

  1. 创立 eureka 我的项目
  2. 配置依赖 pom.xml
  3. 配置 application.yml
    spring:
    application:
    name: eureka-server

server:
port: 2001

eureka:
server:

enable-self-preservation: false   敞开保护模式

instance:

hostname: eureka1     eureka 集群服务器之间 通过此标签辨别

client:

# 不同本身注册  不从本身拉取信息
register-with-eureka: false   
fetch-registry: false


  1. 主程序启用 eureka 服务器
  2. 启动,拜访测试

eureka 注册核心

作用:服务注册和发现

提供者 (Provider)
向注册核心注册本人的地址
消费者 (Consumer)
从注册核心发现其余服务

eureka 的运行机制

注册 一次次重复连贯 eureka 直到注册胜利为止
拉取 每隔 30 秒拉取一次注册表 更新注册信息
心跳 每 30 秒发送一次心跳 3 次收不到心跳 ureka 会删除这个服务
自我保护模式 非凡状况 因为网络不稳固 15 分钟内 85% 服务器呈现心跳异样
爱护所有的注册信息不删除
网络复原后 能够主动退出保护模式
开发测试期间 能够敞开保护模式

搭建 eureka 服务

1.eureka server 依赖
2.yml 文件配置
敞开保护模式
主机名(集群中辨别每台服务器)
针对单台服务器,不向本人注册,不从本人拉取
3. 启动类
@EnableEurekaServer 触发 eureka 服务器的主动配置

服务提供者

2.yml 配置 eureka 连贯地址

主程序增加 @EnableEurekaServer 注解

批改 hosts 文件

127.0.0.1 eureka1
127.0.0.1 eureka2

eureka 和 ” 服务提供者 ” 的高可用(集群)

近程调用

RestTemplate

springboot 提供的近程调用工具,相似 HttpClient

RestTemplate 对 http Rest API 调用做了高度封装,只须要调用一个办法就能够实现申请、响应、json 转换

  • getForObject(url, 转换的类型.class, 提交的参数数据)
  • postForObject(url, 提交的协定体数据, 转换的类型.class)

用 RestTemplate 调用 2,3,4 我的项目

Ribbon

springcloud 提供的工具,对 RestTemplate 进行了加强封装,提供了负载平衡和重试的性能

item-service 高可用

启动参数 –server.port 能够笼罩 yml 中的端口配置

配置启动参数
–server.port=8001
复制一份
–server.port=8002

eureka 高可用

增加两个服务器的 profile 配置文件

配置启动参数和端口
–spring.profiles.active=eureka1 –server.port=2001
–spring.profiles.active=eureka2 –server.port=2002

eureka 客户端注册时,向两个服务器注册

ribbon 服务消费者

ribbon 提供了负载平衡和重试性能 它底层是应用 RestTemplate 进行 Rest api 调用

RestTemplate

RestTemplate 是 SpringBoot 提供的一个 Rest 近程调用工具

罕用办法
getForObject() 执行 get 申请
postForObject() 执行 post 申请

1. 新建 ribbon 我的项目
2.pom.xml
增加 Eureka Discovery Client 和 web 依赖
3.yml 文件

spring:
application:

name: ribbon

server:
port: 3001

eureka:
client:

service-url:
  defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

4. 主程序

@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {

// 创立 RestTemplate 实例,并存入 spring 容器

@Bean
public RestTemplate getRestTemplate() {return new RestTemplate();
}

public static void main(String[] args) {SpringApplication.run(Sp06RibbonApplication.class, args);
}

}
5.controller

@RestController
public class RibbonController {

@Autowired
private RestTemplate rt;

@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
    // 向指定微服务地址发送 get 申请,并取得该服务的返回后果 
    //{1} 占位符,用 orderId 填充
    return rt.getForObject("http://localhost:8001/{1}", JsonResult.class, orderId);
}

@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {
    // 发送 post 申请
    return rt.postForObject("http://localhost:8001/decreaseNumber", items, JsonResult.class);
}

/

@GetMapping("/user-service/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId) {return rt.getForObject("http://localhost:8101/{1}", JsonResult.class, userId);
}

@GetMapping("/user-service/{userId}/score") 
public JsonResult addScore(@PathVariable Integer userId, Integer score) {return rt.getForObject("http://localhost:8101/{1}/score?score={2}", JsonResult.class, userId, score);
}

/

@GetMapping("/order-service/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId) {return rt.getForObject("http://localhost:8201/{1}", JsonResult.class, orderId);
}

@GetMapping("/order-service")
public JsonResult addOrder() {return rt.getForObject("http://localhost:8201/", JsonResult.class);
}

}
6. 启动 并拜访测试

ribbon 负载平衡和测试

负载平衡

  1. 从 eureka 取得地址表
  2. 应用多个地址来回调用
  3. 拿到一个地址,应用 restTemplate 执行近程调用

批改 sp06-ribbon 我的项目

1. 增加 ribbon 起步依赖
2.RestTemplate 设置 @loadBalanced
3. 拜访门路设置为服务 id

@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {


@LoadBalanced // 负载平衡注解
@Bean
public RestTemplate getRestTemplate() {return new RestTemplate();
}

public static void main(String[] args) {SpringApplication.run(Sp06RibbonApplication.class, args);
}

}

拜访门路设置问服务 id

将管制层的本地地址和端口改为服务的 id

例如 “http://item-service/{1}”

pom.xml 文件中增加 spring-retry 依赖

<dependency>

<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>

</dependency>

yml 文件配置 ribbon 重试

spring:
application:

name: ribbon

server:
port: 3001

eureka:
client:

service-url:
  defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
  

ribbon:
MaxAutoRetriesNextServer: 2 更换实例的次数
MaxAutoRetries: 1 以后实例重试次数 尝试失败会更换下一个实例
OkToRetryOnAllOperations: true 可不写 默认支队 GET 申请重试 默认为 false 当设置为 true 时 对 POST 等所有的类型申请进行都重试

主程序设置 RestTemplate 的申请工厂的超时属性

@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {

@LoadBalanced
@Bean
public RestTemplate getRestTemplate() {SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
    f.setConnectTimeout(1000);
    f.setReadTimeout(1000);
    return new RestTemplate(f);
    
    //RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,// 未启用超时,也不会触发重试
    //return new RestTemplate();}

public static void main(String[] args) {SpringApplication.run(Sp06RibbonApplication.class, args);
}

}

item-service 的 ItemController 增加提早代码,以便测试 ribbon 的重试机制

///– 设置随机提早

    if(Math.random()<0.6) {long t = new Random().nextInt(5000);
        log.info("item-service-"+port+"- 暂停"+t);
        Thread.sleep(t);
    }
    
    














退出移动版