最近在看springCoud微服务实战,因此做一些看书笔记吧,都是书上例子,方便理解。
微服务架构中依赖远程调用实现服务之间的通信,所以必然会考虑到通信消耗与连接数。所以容错保护提供了HystrixCollapser来实现请求合并。
源码在这里,有空自己看吧。
下面通过例子来帮助自己理解,记下省的以后忘了。
首先:定义一个实体类User,不多说了。
再次:service 和Service的实现类
import com.ribbon.User;
import java.util.List;
/**
* Created by qhe on 2018/7/27.
*/
public interface UserService {
public User find(Long id);
public List<User> findAll(List<Long> ids);
}
package com.ribbon.user;
import com.ribbon.User;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* Created by qhe on 2018/7/27.
*/
public class UserServiceImpl implements UserService {
@Autowired
private RestTemplate restTemplate;
@Override
public User find(Long id) {
return restTemplate.getForObject
("http//user-service/users/{1}",User.class,id);
}
@Override
public List<User> findAll(List<Long> ids) {
return restTemplate.getForObject
("http//user-service/users?ids={1}",List.class, StringUtils.join(ids,","));
}
}
这里定义了两个接口,一个是单个请求,第二个是批量请求,并且用restTemplate实现了远程调用。
然后第一步开始为请求合并实现一个批量请求
package com.ribbon.user;
import com.netflix.hystrix.HystrixCommand;
import com.ribbon.User;
import java.util.List;
import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey;
/**
* Created by qhe on 2018/7/27.
*/
public class UserBatchCommand extends HystrixCommand<List<User>> {
UserService userService;
List<Long> userIds;
public UserBatchCommand(UserService userService,List<Long> userIds){
super(Setter.withGroupKey(asKey("userBatchCommand")));
this.userIds = userIds;
this.userService = userService;
}
@Override
protected List<User> run() throws Exception {
return userService.findAll(userIds);
}
}
这里实际上就是一个简单的HystrixCommand实现。
第二步开始实现合并器
package com.ribbon.user;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapserKey;
import com.netflix.hystrix.HystrixCollapserProperties;
import com.netflix.hystrix.HystrixCommand;
import com.ribbon.User;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Created by qhe on 2018/7/27.
*/
public class UserCollapseCommand extends HystrixCollapser<List<User>,User,Long> {
private UserService userService;
private Long userId;
public UserCollapseCommand(UserService userService,Long userId){
super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userBatchCommand")).andCollapserPropertiesDefaults(
HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100)//设置时间延迟属性
));
this.userService = userService;
this.userId = userId;
}
@Override
public Long getRequestArgument() {
return userId;//返回给定的单个请求参数
}
/**
*collection参数中保存了延迟时间窗中收集到的所有获取单个User的请求。
* 通过获取这些请求的参数来组织上面我们准备的批量请求命令UserBatchCommand实例
* @param collection
* @return
*/
@Override
protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Long>> collection) {
List<Long> userIds = new ArrayList<>(collection.size());
userIds.addAll(collection.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList()));
return new UserBatchCommand(userService,userIds);
}
/**
* 在批量请求命令UserBatchCommand实例被触发执行完成之后,该方法开始执行,
* 其中users中保存了creatCommand方法中组织的批量请求命令的返回结果,
* 而collection参数则代表了每个被合并的请求,
* 在这里我们通过遍历批量结果users对象,为collection中每个合并前的单个请求设置返回结果,
* 完成批量结果到单个请求结果的转换
* @param users
* @param collection
*/
@Override
protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Long>> collection) {
int count = 0;
for (CollapsedRequest<User,Long> collapsedRequest:collection){
User user = users.get(count++);
collapsedRequest.setResponse(user);
}
}
}
通过合并器,我们可以把多个相同请求合并成一个请求,而这些服务消费者并不用做什么知道什么。
上面是通过继承方式来实现合并,下面通过注解形式来实现,spring的几乎所有功能都有代码实现和注解实现。
package com.ribbon.user;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.ribbon.User;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* Created by qhe on 2018/7/27.
*/
@Service
public class UserServiceA {
@Autowired
RestTemplate restTemplate;
@HystrixCollapser(batchMethod = "findAll",collapserProperties = {
@HystrixProperty(name="timerDelayInMilliseconds",value = "100")})
public User find(Long id){return null;}
@HystrixCommand
public List<User> findAll(List<Long> ids){
return restTemplate.getForObject("http://user-service/user?ids={1}",List.class, StringUtils.join(ids,","));
}