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订单服务
- 新建我的项目
- 配置依赖 pom.xml
- 配置 application.yml
- 配置主程序
- 编写代码
业务层
@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 注册与发现
- 创立eureka我的项目
- 配置依赖 pom.xml
- 配置 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
- 主程序启用 eureka 服务器
- 启动,拜访测试
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负载平衡和测试
负载平衡
- 从 eureka 取得地址表
- 应用多个地址来回调用
- 拿到一个地址,应用 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);
}
发表回复