赞
踩
服务配置元数据,在网关中拦截请求,根据用户对应的级别,分发到不同的服务,实现灰度发布。
eureka: client: service-url: defaultZone: http://localhost:7900/eureka/ registry-fetch-interval-seconds: 30 enabled: true #,http://localhost:7901/eureka/,http://localhost:7902/eureka/ instance: lease-renewal-interval-in-seconds: 30 --- spring: profiles: v1 eureka: instance: metadata-map: version: v1 server: #服务端口 port: 8003 --- spring: profiles: v2 eureka: instance: metadata-map: version: v2 server: #服务端口 port: 8004
引入maven依赖
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
编写filter
@Component public class GrayFilter extends ZuulFilter { @Override public String filterType() { return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); int userId = Integer.parseInt(request.getHeader("userId")); // 根据用户id 查 规则 查库 v1,meata // 金丝雀 if (userId == 1){ RibbonFilterContextHolder.getCurrentContext().add("version","v1"); // 普通用户 }else if (userId == 2){ RibbonFilterContextHolder.getCurrentContext().add("version","v2"); } return null; } }
http://localhost:9100/service-sms/test/sms-test3
思路:在请求进入的时候,通过spring aop技术拦截请求,将请求的用户id和对应的version通过ThreadLocal进行设置值。在请求出口处,获取到ThreadLocal内的值,通过ribbon进行服务选择。
public class GrayRule extends AbstractLoadBalancerRule { /** * 根据用户选出一个服务 * @param iClientConfig * @return */ @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } @Override public Server choose(Object key) { return choose(getLoadBalancer(),key); } public Server choose(ILoadBalancer lb, Object key){ System.out.println("灰度 rule"); Server server = null; while (server == null){ // 获取所有 可达的服务 List<Server> reachableServers = lb.getReachableServers(); // 获取 当前线程的参数 用户id verion=1 Map<String,String> map = RibbonParameters.get(); String version = ""; if (map != null && map.containsKey("version")){ version = map.get("version"); } System.out.println("当前rule version:"+version); // 根据用户选服务 for (int i = 0; i < reachableServers.size(); i++) { server = reachableServers.get(i); // 用户的version我知道了,服务的自定义meta我不知道。 // eureka: // instance: // metadata-map: // version: v2 // 不能调另外 方法实现 当前 类 应该实现的功能,尽量不要乱尝试 Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata(); String version1 = metadata.get("version"); // 服务的meta也有了,用户的version也有了。 if (version.trim().equals(version1)){ return server; } } } // 怎么让server 取到合适的值。 return server; } }
@Component
public class RibbonParameters {
private static final ThreadLocal local = new ThreadLocal();
// get
public static <T> T get(){
return (T)local.get();
}
// set
public static <T> void set(T t){
local.set(t);
}
}
@Aspect @Component public class RequestAspect { // 匹配返回值+包名+类名+方法名 @Pointcut("execution(* com.mashibing.apipassenger.controller..*Controller*.*(..))") private void anyMehtod() { } @Before(value = "anyMehtod()") public void before(JoinPoint joinPoint) { System.out.println("目标方法名为:" + joinPoint.getSignature().getName()); System.out.println("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName()); System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName()); System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers())); //获取传入目标方法的参数 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { System.out.println("第" + (i + 1) + "个参数为:" + args[i]); } System.out.println("被代理的对象:" + joinPoint.getTarget()); System.out.println("代理对象自己:" + joinPoint.getThis()); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String version = request.getHeader("version"); Map<String, String> map = new HashMap<>(); map.put("version", version); RibbonParameters.set(map); } // 环绕方法不需要,是为了测试AOP的用法写的 /** * 环绕方法,可自定义目标方法执行的时机 * * @param pjd JoinPoint的子接口,添加了 * Object proceed() throws Throwable 执行目标方法 * Object proceed(Object[] var1) throws Throwable 传入的新的参数去执行目标方法 * 两个方法 * @return 此方法需要返回值, 返回值视为目标方法的返回值 */ @Around(value = "anyMehtod()") public Object aroundMethod(ProceedingJoinPoint pjd) { Object result = null; try { //前置通知 System.out.println("---------------目标方法执行前..."); //执行目标方法 result = pjd.proceed(); //用新的参数值执行目标方法 // result = pjd.proceed(new Object[]{"newSpring", "newAop"}); //返回通知 System.out.println("目标方法返回结果后..."); } catch (Throwable e) { //异常通知 System.out.println("执行目标方法异常后..."); throw new RuntimeException(e); } //后置通知 System.out.println("目标方法执行后..."); return result; } }
public class GrayRibbonConfiguration {
@Bean
public IRule ribbonRule(){
return new GrayRule();
}
}
@RibbonClient(name = "service-sms",configuration = GrayRibbonConfiguration.class)
public class ApiPassengerApplication {
引入maven依赖
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
在切面中添加代码
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String version = request.getHeader("version");
if (version.trim().equals("v2")) {
RibbonFilterContextHolder.getCurrentContext().add("version", "v2");
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。