服务注册与发现-Spring Cloud Netflix-Eureka

关键词:Eureka    服务发现    服务注册


Spring Cloud是基于Spring Boot做为开发框架的,在Spring Cloud的很多功能实现中,大量使用了Spring Boot的自动注入功能(AutoConfigure)。Spring Cloud中,服务与服务之间的通信使用的是http协议。

Eureka具有服务注册与服务发现,并且可以作为注册中心。Eureka分为两种角色,服务端(Eureka Server)和客户端(Eureka Client)。Eureka服务端可以看做是一个注册中心,只是这个注册中心需要依赖于Spring Boot项目,我们在使用Eureka服务端功能的时候,需要创建一个Spring Boot项目然后引入相关依赖,修改配置,使用注解,然后运行这个Spring Boot项目即可。关于我们项目自己的服务提供者和服务消费者,对Eureka来说,都是Eureka客户端。在我们自己的项目中引入相关依赖,然后使用注册,Eureka客户端功能会自动的将我们的服务注册到Eureka服务端中,并完成我们的服务消费者服务发现的功能。

Eureka服务端对自己来说,也是Eureka客户端。所以在spring-cloud-starter-netflix-eureka-server依赖中还包含了spring-cloud-netflix-eureka-client的内容,并且在Eureka Server自动注入的时候,还会依赖于client端自动注入的bean。

Eureka客户端通过调用http接口与Eureka服务端进行通信,完成服务注册与获取等功能。默认使用Jersey进行http通信。服务提供者使用HTTP POST请求(/eureka/apps/{appName})注册服务。每隔30秒,它必须使用HTTP PUT请求(/eureka/apps/{appName}/{id})刷新其注册,与Eureka服务端保持心跳联系。通过使用HTTP DELETE请求(/eureka/apps/{appName}/{id})或实例注册超时来删除注册。服务消费者可以通过使用HTTP GET请求(/eureka/apps或/eureka/apps/{appName})检索已注册的服务实例。

Eureke客户端调用请求接口:EurekaHttpClientAbstractJerseyEurekaHttpClient及其实现类

Eureke服务端接口资源定义:ApplicationsResourceApplicationResourceInstanceResource及其同一个包下的其他Resource


█ Eureka服务端

角色:注册中心

使用:

(1)创建maven项目,修改pom.xml文件,引入相应的依赖

<properties>
    <java.version>1.8</java.version>
    <!-- Spring Cloud版本 -->
    <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <!-- 添加eureka-server依赖,引入jar包 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

spring-cloud-starter-netflix-eureka-server依赖中已经包含了Spring Boot的依赖,为了避免版本冲突带来的问题,建议无需再在项目中单独引入Spring Boot依赖。spring-cloud-starter-netflix-eureka-server中包含了如下的依赖:

(2)编写application.yml配置

因为是Spring Boot项目,所以使用yaml文件作为配置文件。

# Eureka作为Spring Boot项目对外提供服务,需要设置端口号,默认为8080
# 因为在Spring Cloud中服务之间通信使用http协议,所以每个项目需要是web项目
server:
  port: 8899

eureka:
  client:
    // 是否进行注册服务,当前服务不作为eureka 客户端,不进行服务注册  
    register-with-eureka: false
    // 是否获取注册服务列表
    fetch-registry: false

(3)编写Spring Boot启动类

package myeureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
// Spring Boot注解
@SpringBootApplication
// 开启Eureka server功能
@EnableEurekaServer
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

启动的时候,如果出现下图所示的错误,此时,删除本地maven仓库中对应的jar文件即可:

(4)启动成功之后,在浏览器访问:localhost:8899,会看见如下图所示页面。此页面为Eureka服务端的仪表盘,在里面可以看见已经注册的服务提供者的信息,以及Eureka服务集群的情况:

经过上面的几个简单的步骤,就能搭建一个Eureka服务作为注册中心了。

补充:将当前Eureka服务端也作为客户端服务进行注册,修改yml配置:

eureka:
  client:
    // 注册服务,默认为true  
    register-with-eureka: true
    fetch-registry: false
    service-url:
      // eureka 服务端的服务地址,请求路径为/eureka/。因为此时的服务端就是本服务自己,所以这里的服务地址就是当前服务  
      defaultZone: http://localhost:${server.port}/eureka/

重启服务之后,访问:localhost:8899/,此时在服务列表会出现当前服务:

原理:

(1)从@EnableEurekaServer注解开始,通过@Import,在Spring启动的时候会被加载:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}

(2)EurekaServerMarkerConfiguration就做了一件事情,创建Marker对象,Spring会扫描@Bean注解,将Marker对象注册成Spring bean,加入Spring容器中:

public class EurekaServerMarkerConfiguration {
    public EurekaServerMarkerConfiguration() {
    }

    @Bean
    public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
        return new EurekaServerMarkerConfiguration.Marker();
    }

    class Marker {
        Marker() {
        }
    }
}

(3)此时,如果你不熟悉Spring Boot的自动配置功能,可能会一头雾水,就这?熟悉Spring Boot自动配置的同学,应该了解在项目的META-INF文件夹下,如果存在一个文件为spring.factories,里面的内容是键值对形式,键为org.springframework.boot.autoconfigure.EnableAutoConfiguration,这样Spring Booot在启动的时候,会根据value的值,自动完成配置,创建Bean等等。找到spring-cloud-starter-netflix-eureka-server的jar包,可以看见:

spring.factories的内容为下面所示:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration

(4)EurekaServerAutoConfiguration

EurekaServerAutoConfiguration类的内容比较多,主要完成的就是多个bean的创建。我们一段段来看:

  • 类上注解:
// Spring会加载EurekaServerInitializerConfiguration
@Import({EurekaServerInitializerConfiguration.class})
// 当Spring 容器中存在Marker类型的bean时,Spring才会加载EurekaServerAutoConfiguration
// 因为在启动类上使用了@EnableEurekaServer注解,所以Spring容器中会存在Merker类型的bean
@ConditionalOnBean({Marker.class})
// 配置的加载,将yml中的配置,设置到EurekaDashboardProperties、InstanceRegistryProperties两个bean对应的属性上。
@EnableConfigurationProperties({EurekaDashboardProperties.class, InstanceRegistryProperties.class})
// 当前类可以使用类路径下/eureka/server.properties路径下的配置信息
@PropertySource({"classpath:/eureka/server.properties"})
public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
    ......
}
  • 通过@Autowired自动注入相应类型的bean
// ApplicationInfoManager是eureka-client jar包下面的类
// @Singleton
// public class ApplicationInfoManager
@Autowired
private ApplicationInfoManager applicationInfoManager;
@Autowired
private EurekaServerConfig eurekaServerConfig;
@Autowired
private EurekaClientConfig eurekaClientConfig;
@Autowired
private EurekaClient eurekaClient;
@Autowired
private InstanceRegistryProperties instanceRegistryProperties;

其中的ApplicationInfoManagerEurekaClientConfigEurekaClient 是在EurekaClientAutoConfiguration里面完成bean的注册的。EurekaClientAutoConfiguration在spring-cloud-netflix-eureka-client jar包下面。从这里可以看出,Eureka Server依赖于Eureka Client,无法单独使用。

  • 创建仪表盘页面的访问controller,即在使用步骤4中通过浏览器请求看到的页面。可通过eureka.dashboard.enabled=false关闭此功能,默认为true开启:
@Bean
@ConditionalOnProperty(
    prefix = "eureka.dashboard",
    name = {"enabled"},
    matchIfMissing = true
)
public EurekaController eurekaController() {
    return new EurekaController(this.applicationInfoManager);
}

访问路径可以通过eureka.dashboard.path配置,默认为/,所以我们在浏览器访问:localhost:8899可以获取到页面。若修改配置eureka.dashboard.path=myeureka,则访问路径为:localhost:8899/myeureka:

@Controller
@RequestMapping({"${eureka.dashboard.path:/}"})
public class EurekaController {
    @Value("${eureka.dashboard.path:/}")
    private String dashboardPath = "";
    private ApplicationInfoManager applicationInfoManager;

    public EurekaController(ApplicationInfoManager applicationInfoManager) {
        this.applicationInfoManager = applicationInfoManager;
    }
    
    // get请求获取页面信息
    @RequestMapping(
        method = {RequestMethod.GET}
    )
    public String status(HttpServletRequest request, Map<String, Object> model) {
        // 下面内容的主要工作就是获取相关值放进model中,这样在页面可以获取到 
        
        this.populateBase(request, model);
        this.populateApps(model);

        StatusInfo statusInfo;
        try {
            statusInfo = (new StatusResource()).getStatusInfo();
        } catch (Exception var5) {
            statusInfo = Builder.newBuilder().isHealthy(false).build();
        }

        model.put("statusInfo", statusInfo);
        this.populateInstanceInfo(model, statusInfo);
        this.filterReplicas(model, statusInfo);
        // 这里返回到类路径下eureka文件夹下面的status视图页面
        // 这一块是Spring MVC的知识了
        return "eureka/status";
    }
    }

在jar包里面可以找到:

  • 创建EurekaServerConfig类型的bean,配置Eureka服务端:
@Configuration(
    proxyBeanMethods = false
)
protected static class EurekaServerConfigBeanConfiguration {
    protected EurekaServerConfigBeanConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) {
        // @ConfigurationProperties("eureka.server")
        // public class EurekaServerConfigBean implements EurekaServerConfig
        // 在bean创建的时候,会通过eureka.server开头的配置对EurekaServerConfigBean中的属性进行设值
        EurekaServerConfigBean server = new EurekaServerConfigBean();
        // 通过配置:eureka.client.register-with-eureka设置。默认为true
        if (clientConfig.shouldRegisterWithEureka()) {
            // 注册失败重试5次
            server.setRegistrySyncRetries(5);
        }

        return server;
    }
}
  • 创建编码解码器,在网络中数据的传输需要编码和解码,用于Eureka服务端与Eureka客户端数据传输时的编码和解码:
@Bean
public ServerCodecs serverCodecs() {
    return new EurekaServerAutoConfiguration.CloudServerCodecs(this.eurekaServerConfig);
}
  • 创建Eureka服务的副本的过滤器。用于多个Eureka服务时,即Eureka集群:
@Bean
@ConditionalOnMissingBean
public ReplicationClientAdditionalFilters replicationClientAdditionalFilters() {
    return new ReplicationClientAdditionalFilters(Collections.emptySet());
}
  • 用于服务注册功能。此服务注册包含了集群中副本的注册以及客户端服务的注册:
@Bean
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(ServerCodecs serverCodecs) {
    this.eurekaClient.getApplications();
    return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
  • Eureke节点集合:
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs, ReplicationClientAdditionalFilters replicationClientAdditionalFilters) {
    return new EurekaServerAutoConfiguration.RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager, replicationClientAdditionalFilters);
}
  • Eureka服务的上下文:
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
    return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.a
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值