Spring 封装、揉和了一批开源项目,其中以Netflix开源的为主,比如zuul、eureka、hystrix、robbin等;然后就有了现在的Spring cloud微服务架构。这也充分展现了Spring的揉合能力。
Spring cloud通过封装使这些项目融入spring的bean管理机制中,从而方便使用。这套微服务的核心功能还是使用这些项目的。
由本篇的标题可以想到本篇就是不使用Spring的注解和配置来使用这套微服务。看看现在网上关于Spring cloud的示例,千篇一律那几行注解和代码。确实方便了使用。
本篇主要从微服务的调用端来讲解的,主要涉及如下几点:
- 全局配置,包括服务注册中心配置;
- 初始化服务发现客户端;
- 实例化负载均衡调用实现类;
- 实例化某个具体调用requset,再对根据服务均衡器选择的服务提供者进行调用;
如果你使用过dubbo的泛化调用,会发现很相似;难怪有人专门对比使用Spring cloud和dubbo来实现微服务。
如下为编码实现的例子,很多说明在注解中;
EurekaClientConfigBean bean = new EurekaClientConfigBean();
Map<String, String> map = new HashMap<String, String>();
//eureka服务注册中心地址
map.put(EurekaClientConfigBean.DEFAULT_ZONE,"http://xx.xx.xxx.xx:1062/eureka/,http://xx.xx.xxx.xx:1063/eureka/,http://xx.xx.xxx.xx:1064/eureka/");
bean.setServiceUrl(map);
EurekaInstanceConfigBean instanceConfigBean = new EurekaInstanceConfigBean(new InetUtils(new InetUtilsProperties()));
instanceConfigBean.setPreferIpAddress(true);
ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(instanceConfigBean);
//以上完成全局配置,基本使用默认配置
//实例化eureka服务消费端,查询Eureka Server中的服务实例列表
final DiscoveryClient client = new DiscoveryClient(applicationInfoManager, bean);
Provider<EurekaClient> eurekaClientProvider = new Provider<EurekaClient>() {
@Override
public synchronized EurekaClient get() {
return client;
}
};
IClientConfig clientConfig = new DefaultClientConfigImpl();
clientConfig.loadDefaultValues();
//设置vipAddress,该值对应spring.application.name配置,指定某个应用
clientConfig.set(CommonClientConfigKey.DeploymentContextBasedVipAddresses,"ZPROVIDER");
//根据eureka client获取服务列表,client以provide形式提供
DiscoveryEnabledNIWSServerList discoveryEnabledNIWSServerList = new DiscoveryEnabledNIWSServerList(clientConfig, eurekaClientProvider);
//实例化负载均衡器接口ILoadBalancer,这里使用了ZoneAwareLoadBalancer,这也是spring cloud默认使用的。该实现可以避免了跨区域(Zone)访问的情况。
//其中的参数分别为,1)某个具体应用的客户端配置,2)负载均衡的处理规则IRule对象,负载均衡器实际进行服务实例选择任务是委托给了IRule实例中的choose函数来实现,
//这里使用了ZoneAvoidanceRule,3)实例化检查服务实例是否正常服务的IPing接口对象,负载均衡器启动一个用于定时检查Server是否健康的任务。该任务默认的执行间隔为:10秒。
//这里没有做真实的ping操作,他只是检查DiscoveryEnabledNIWSServerList定时刷新过来的服务列表中的每个服务的状态;4)如上,ServerList接口有两个方法,分别为
//获取初始化的服务实例清单和获取更新的服务实例清单;5)ServerListFilter接口实现,用于对服务实例列表的过滤,根据规则返回过滤后的服务列表;6)ServerListUpdater服务更新器接口
//实现动态获取更新服务列表,默认30秒执行一次
ILoadBalancer loadBalancer = new ZoneAwareLoadBalancer(clientConfig, new ZoneAvoidanceRule(), new NIWSDiscoveryPing(),
discoveryEnabledNIWSServerList,new DefaultNIWSServerListFilter(), new EurekaNotificationServerListUpdater(eurekaClientProvider));
//实例化request client,他对由负载均衡器选择的Server进行请求,Spring cloud封装了apache HttpClient和OkHttp两种实现
RibbonLoadBalancingHttpClient ribbonLoadBalancingHttpClient = new RibbonLoadBalancingHttpClient(clientConfig, new DefaultServerIntrospector());
ribbonLoadBalancingHttpClient.setLoadBalancer(loadBalancer);
// OkHttpLoadBalancingClient okHttpLoadBalancingClient = new OkHttpLoadBalancingClient(clientConfig, new DefaultServerIntrospector());
// okHttpLoadBalancingClient.setLoadBalancer(loadBalancer);
//实例化某个具体request的上下文,如果对应到开放平台上,这些信息就是开放某个具体接口时,录入的API信息
RibbonCommandContext context = new RibbonCommandContext("ZPROVIDER","get", "/test/weber", Boolean.FALSE, new HttpHeaders(),
new LinkedMultiValueMap(), null, new ArrayList<RibbonRequestCustomizer>(), null);
RibbonCommandContext context1 = new RibbonCommandContext("ZPROVIDER","get", "/sum?v=2&vv=3", Boolean.FALSE, new HttpHeaders(),
new LinkedMultiValueMap(), null, new ArrayList<RibbonRequestCustomizer>(), null);
BufferedReader br = null;
String result = "";
try {
//实例化request,对Service请求调用
RibbonApacheHttpResponse response = ribbonLoadBalancingHttpClient.executeWithLoadBalancer(new RibbonApacheHttpRequest(context1));
// OkHttpRibbonResponse response = okHttpLoadBalancingClient.executeWithLoadBalancer(new OkHttpRibbonRequest(context1));
//如果服务接口输出json或xml,可以拿到显示
br = new BufferedReader(new InputStreamReader(response.getInputStream()));
String line = null;
while((line = br.readLine())!=null){
result+=line;
}
System.out.println("Result: "+result);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null!=br){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
zuul实现了网关框架,主要逻辑为执行pre、route、post三种类型的filter,且可以动态加载filter,使用方可以实现自己的filter。
Spring cloud封装实现的route类型filter,默认使用了ribbon对eureka 服务发现的负载均衡client。
Spring cloud在结合了ribbon的负载均衡实现中,封装增加了HttpClient和OkHttp两种HTTP请求端实现。
Spring cloud中还集成了Feign,方便的使用HTTP请求调用远程服务,且可以灵活的使用和自定义各种编解码器实现入参和出差的序列化和反序列化。
做上面的代码示例的想法来源于现在负责的网关项目中一些需求想法,之前网关只适配了dubbo类型的rpc服务集群,目前一些新项目开始试行spring cloud架构,所以网关在做对应的适配。图例如下: