Spring-cloud&Netflix 源码解析之Eureka:一个注解加载Eureka client

一般我们的都会被告知使用spring cloud app 如果需要服务服务注册发现功能,只需简单的一个 @EnableEurekaClient 的annotation,就可以搞定。服务启动时会自动注册到eureka服务,服务消费者只需要使用该名字加方法名就可以调用到服务。代码基本不用加任何东西,很神奇的样子!于是有点好奇一个本文重点关注在spring cloud中Eureka client是如何被注入,来供服务使用的。

本文主要了解下在spring cloud下用户开发一个自己的服务,用一个annotation怎么就能自动的完成服务的注册和发现。怎样偷偷的集成了一个eureka的client进去的。说实话对于这个annotation虽然看着对使用者是很简单,但是可能对一般使用惯了API的人,封装太多了倒有点不踏实。

1 Eureka client简介

Eureka client 负责与Eureka Server 配合向外提供注册与发现服务接口。首先看下eureka client是怎么定义,Netflix的 eureka client的行为在LookupService中定义,Lookup service for finding active instances,定义了,从outline中能看到起“规定”了如下几个最基本的方法。
服务发现必须实现的基本行为:

lookupservice_outline

com.netflix.discovery.DiscoveryClient是netflix使用的客户端,从其class的注释可以看到他主要做这几件事情:
a) Registering the instance with Eureka Server
b) Renewalof the lease with Eureka Server
c) Cancellation of the lease from Eureka Server during shutdown

2 Eureka Client 在Spring cloud中

看到spring cloud自己又搞了个org.springframework.cloud.client.discovery.
接口,其接口定义如下
其实现类是 org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient。看上去spring cloud是自己做了个新client,来和Eureka server通信来实现服务注册和发现吗?里面代码稍微多看一点会看到其实里面还是使用了netflix原生的 com.netflix.discovery.EurekaClient。

其实这种方式在spring cloud中运用很多。spring cloud里面挺多对象,都是自己定义了一个接口,定义了其在spring cloud上下文中赋予的新的行为要求,但是其实现类其实都是使用netflix原生的对应对象,包括里面的ServiceInstance等,都是有自己的定义 但是实现类EurekaServiceInstance 其实也是对netflix原生的com.netflix.appinfo.InstanceInfo 的封装。因此springcloud中的对象更像是一个wrapper。有点像那种被改造过的decorator pattern

因此要看下spring cloud中怎样加载一个eureka client,其实,先看下如何加载一个EurekaDiscoveryClient

3 EurekaDiscoveryClient在spring cloud的注入过程

如下的是一般写一个服务,在服务的启动类中,用户要做的所有事情就是在自己的app中使用@EnableEurekaClient

这样一个annotation。我们试着看下这个annotation后面怎么把这个EurekaDiscoveryClient 注入的。
可以看到这个自定义的annotation @EnableEurekaClient里面没有内容。只是个属于那种标记类型 的注释,他的作用就是开启Eureka discovery的配置,正是通过这个标记,autoconfiguration就可以加载相关的Eureka类。那我们看下他是怎么做到的。

看到EnableEurekaClient这个自定义anntotaion的定义,用到了另一个自定义的注解:@EnableDiscoveryClient。看看这个自定义注解

这个注解import了EnableDiscoveryClientImportSelector.class这样一个类,其实就是通过这个类来加载需求要的bean。Import的用法和我们原来用xml的方式来聚合两个类似的配置类。

看到这里有覆盖了父类SpringFactoryImportSelector的一个方法isEnabled,其实标记体现的也就是这里,在配置的环境中找这个key是否被配置,注意,默认是TRUE,也就是只要import了这个配置,就会enable。

在其父类org.springframework.cloud.commons.util.SpringFactoryImportSelector
的String[] selectImports(AnnotationMetadata metadata)方法中正是根据这个标记类判定是否加载如下定义的类。

 

 

调用loadFactoryNames其实加载META-INF/spring.factories下的class。

org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader)

spring-cloud-netflix-eureka-client\src\main\resources\META-INF\spring.factories中配置,可以看到EnableAutoConfiguration的包含了EurekaClientConfigServerAutoConfiguration。

EurekaClientAutoConfiguration分别会依次注入配置EurekaClientConfigBean、 EurekaInstanceConfigBean和DiscoveryClient

4.? 调用过程

至此就找到了Eureka相关类是在哪里定义的,怎样通过@EnableEurekaClient 这个注解来控制加载的。但是在服务的congtext中这部分又是如何被调用到的呢?如果要分析这部分,就有点想我没试图从原来的spring的application.xml去试图追寻其中定义的bean是如何在context中创建,又如何被被根据配置赋予属性,建立bean之间的关系。

其实在spring cloud中使用的annotation就是原来大家属性的xml配置的另外一种so called alternative。

这个调用关系真的是非常长,非常繁琐的,明显不是本文讨论的重点,这是springIOC的核心实现,详细可以参照spring core相关的东西。但是为了完整期间,还是最粗糙的把这个调用关系贴出来。能看到在自己写的一个服务的main函数开始如果使用spring 上下文来加载那几个eureka的类。只是简单看下这个过程,简化了很多,所以这里的调用过程也是一个简单的链路。

可以看到不管是原来的xml的方式还是现在这种annotation的方式,abstract的context还是同样的逻辑,这个方法是最典型的模板方法,调用的各个方法都是在子类中定义。进一步验证了annotation于xml也都只是一种配置的方式,是给开发人员的接口,spring IOC的东西没用变。其实从调用链路上各个类的package从属也能看出端倪。

这个就是我们前面看到的import 类并实例化的地方。看到在processImports中会对这里import的类进行实例化。

 

原创文章。为了维护文章的版本一致、最新、可追溯,转载请注明: 转载自idouba

本文链接地址: Spring-cloud&Netflix 源码解析之Eureka:一个注解加载Eureka client


, , , , ,

Trackbacks/Pingbacks

  1. Spring-cloud & Netflix 源码解析之Eureka | idouba - 2016年4月15日

    […] Spring-cloud & Netflix 源码解析:一个注解加载Eureka client […]

  2. Spring-cloud & Netflix 源码解析:Eureka client 到Server的调用过程 | idouba - 2016年3月17日

    […] idouba on 2016年3月10日 in microservice 在前面一篇文章中介绍了spring […]

发表评论