1.springCloud?
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、熔断器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并
没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
2.springboot和springcloud之间的关系
Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,可以不基于Spring Boot吗?不可以。
Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
3.常用的springcloud的组件
服务发现——Netflix Eureka
服务调用——Netflix Feign
熔断器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config
消息总线 —— Spring Cloud Bus
4.springcloud和double对比
Dubbo只是实现了服务治理,而Spring Cloud下面有17个子项目(可能还会新增)分别覆盖了微服务架构下的方方面面,服务治理只是其中的一个方面,一定程度来说,Dubbo只是Spring CloudNetflix中的一个子集。
唯一Dubbo的一点优势就是,调用方式是rpc,底层是通过二进制传输的,效率极高,而springcloud是通过rest API进行传输的效率低
Eureka服务端的开发
开发步骤:
1.创建Eureka server 工程
2.创建启动类,在启动类上添加注解@EnableEurekaServer
3.提供配置文件,在配置文件中指定EurekaServer的相关配置
4.启动工程,访问6868 端口 查询EurekaServer的注册端口号
注意:在父工程中导入springcloud版本
启动localhost:6868
将业务微服务注册到Eureka中
启动类上添加注解:
@EnableEurekaClient
配置文件
保护模式:
Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)
服务间的调用:
前提:必须将服务提供者,服务调用者注册到Eureka Server
1、目前项目提供RestApi,采用发送http请求请求目标微服务,弊端:维护多个ip port
2、解决:使用Feign简化开发--通过接口产生代理对象(发送http请求,请求ip地址端口从EurekaServerl)
测试通过问答微服务调用基础微服务
1.服务的提供者,提供正确的restAPI
2.服务调用者,映入feign,启动类上添加注解@EnableFeignClient
3.创建接口
4.需要调用接口注入产生代理对象即可
在问答中添加feign
启动类添加注解:
编写接口
测试可以查询数据
实现服务的之间的调用
负载均衡:
在feign框架中包含的组件Ribbon实现微服务的负载均衡
需求分析:
1.单向添加好友,和添加不喜欢的好友
/**
* @param friendid 对方好友id
* @param type 1:喜欢(关注)好友 2:不喜欢(屏蔽好友)
* @return
*/
@PutMapping("/like/{friendid}/{type}")
public Result addFriend(@PathVariable String friendid, @PathVariable String type){
//问题 如何获取当前用户id
//用户登陆成功后,返回jwt token。解析token获取用户id
Claims claims = (Claims) request.getAttribute("claims");
if(claims!=null && claims.get("roles").equals("user")){
String userid = claims.getId();
if(type.equals("1")){
friendService.addFriend(userid, friendid);
return new Result(true, StatusCode.OK, "添加好友成功");
}else{
//不喜欢此好友,好友推荐列表中不再出现
friendService.addNofriend(userid, friendid);
return new Result(true, StatusCode.OK, "屏蔽好友成功");
}
}
return new Result(false, StatusCode.ACCESSRROR, "无权操作");
}
service层
@Autowired
private FriendDao friendDao;
@Autowired
private NoFriendDao noFriendDao;
//单向添加好友
@Transactional
public void addFriend(String userid, String friendid) {
Friend friend = new Friend();
friend.setUserid(userid);
friend.setFriendid(friendid);
friend.setIslike("0");//单向喜欢
friendDao.save(friend);
//查询是对方好友是否关注我
int count = friendDao.selectCount(friendid,userid);
if (count > 0){
//互粉状态
//修改双方的状态islike
friendDao.updateIsLike(friendid,userid,"1");
friendDao.updateIsLike(userid,friendid,"1");
}
}
/**
* 添加不喜欢的好友
* @param userid
* @param friendid
*/
public void addNofriend(String userid, String friendid) {
NoFriend noFriend = new NoFriend();
noFriend.setFriendid(friendid);
noFriend.setUserid(userid);
noFriendDao.save(noFriend);
}
dao层
public interface FriendDao extends JpaRepository {
@Query("select count(*) from Friend f where f.userid = ?1 and f.friendid = ?2")
int selectCount(String friendid, String userid);
@Query("update Friend f set f.islike = ?3 where f.userid = ?2 and f.friendid = ?1")
@Modifying
void updateIsLike(String friendid, String userid, String s);
}
2.删除好友的实现:
实现添加到nofriend中并且在在更改对方的好友的islike为0
/**
* 删除好友的实现
*/
@DeleteMapping("/{friendid}")
public Result delete(@PathVariable String friendid){
Claims claims = (Claims) request.getAttribute("claims");
if(claims!=null && claims.get("roles").equals("user")){
String userid = claims.getId();
friendService.deleteFriend(userid,friendid);
return new Result(true, StatusCode.OK,"删除成功");
}
return new Result(false, StatusCode.ACCESSRROR, "无权操作");
}
/**
* 删除好友
* @param userid
* @param friendid
*/
@Transactional
public void deleteFriend(String userid, String friendid) {
friendDao.deleteFriend(userid,friendid);
friendDao.updateIsLike(friendid,userid,"0");
addNofriend(userid,friendid);//想不喜欢的表中添加记录
}
@Query("delete from Friend f where f.userid = ?1 and f.friendid = ?2")
void deleteFriend(String userid, String friendid);
3.用户微服务的粉丝数和关注数的改变
在user微服务模块
/**
* 添加粉丝数
*/
@PostMapping("/incfans/{userid}/{x}")
public void incFanscount(@PathVariable String userid,@PathVariable int x){
userService.incFanscount(userid,x);
}
/**
* 添加关注数
*/
@PostMapping("/incfollow/{userid}/{x}")
public void incFollowercount(@PathVariable String userid,@PathVariable int x){
userService.incFollowcount(userid,x);
}
/**
* 跟改粉丝数
*/
@Modifying
@Query("update User u set u.fanscount = u.fanscount+?2 where u.id=?1")
public void incFanscount(String userid,int x);
/**
* 更改关注数
*/
@Modifying
@Query("update User u set u.followcount = u.followcount + ?2 where u.id = ?1")
public void incFollowcount(String userid,int x);
我们在friend我服务模块中添加接口,用来代理use微服务中的方法
@FeignClient("tensquare-user")
public interface UserClient {
/**
* 增加粉丝数据
*/
@PostMapping("/user/incfans/{userid}/{x}")
public void incFanscount(@PathVariable("userid") String userid,@PathVariable("x") int x);
/**
* 增加关注数
*/
@PostMapping("/user/incfollow/{userid}/{x}")
public void incFollowercount(@PathVariable("userid") String userid,@PathVariable("x") int x);
}
注意:添加@FignClient注解用于指定代理的用户模块
@PathVaribale中属性值,必须添加,不然就会报错
在friendService的addFriend方法中
//增加关注数和粉丝数 userClient.incFanscount(userid,1); userClient.incFollowercount(friendid,1);
在deleteService方法减少粉丝和关注数
userClient.incFanscount(userid,-1); userClient.incFollowercount(friendid,-1);
注意:这些操作一定要在方法上添加注解
1.你在项目中那些模块中用到了SpringCloud组件
服务注册组件Eureka 服务发现组件Feign 熔断器 网关 SpringCloudConfig (集中配置
管理) SpringCloudBus(消息总线)
2.你在项目中哪个业务场景使用到微服务间的调用
交友微服务 添加好友,在交友微服务中调用用户微服务的更改粉丝数与关注数的方法。