SpringCloud学习笔记(三)—— Eureka的搭建以及部分源码解读

1、Eureka介绍

服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现。

<<上传失败了的图片>>

Application Service 相当于服务提供者/api

Application Client 相当于服务消费者/app

Make Remote Call,其实就是实现服务的使用/比如httpClient,restTemplate

us-east-1 Eureka 集群服务

us-east-1c、us-east-1d、us-east-1e 就是具体的某个eureka

PS:图片还是上传不到 后续补回

 

2、Eureka-Server搭建

2.1、pom.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>team.csrj</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>eureka-server7001</artifactId>
<packaging>jar</packaging>
<name>eureka-server7001</name>
<description>eureka服务端</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>

2.2、application.yml

server:
  port: 7001
spring:
  application:
    name: eureka-server
eureka:
  client:
    # 表示是否将自己注册到Eureka Server,默认为true。
    register-with-eureka: false
    # 表示是否从Eureka Server获取注册信息,默认为true。
    fetch-registry: false
    # 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。默认是http://localhost:8761/eureka ;多个地址可使用,分隔,后续会讲解这个路径的来源
    service-url:
      defaultZone: http://localhost:${server.port}/eureka/

2.3、程序入口

packageteam.csrj.eurekaserver7001;

importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@EnableEurekaServer
@SpringBootApplication
publicclassEurekaServer7001Application{

publicstaticvoidmain(String[]args){
SpringApplication.run(EurekaServer7001Application.class,args);
}
}

2.4、运行(localhost:7001)

<<效果图,可惜上传失败,后续补回>>

3、eureka-client(服务提供者/消费者)搭建

3.1、pom.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>producer-7001</name>
<description>服务提供者demo</description>
<parent>
<groupId>team.csrj</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>producer-7001</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>

3.2、application.yml



server:
    port: 8001
    servlet:
      jsp:
        init-parameters:
              development: true


spring:
    application:
        name: producer-8001
    profiles: dev
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
        default-property-inclusion: NON_NULL
    redis:
        database: 1
        host: ${REDIS_HOST:127.0.0.1}
        port: ${REDIS_PORT:6379}
        jedis:
          pool:
            max-active: 8
            max-wait: -1ms
            max-idle: 0
            min-idle: 8
        lettuce:
          shutdown-timeout: 100ms
          pool:
            max-active: 8
            max-wait: -1ms
            max-idle: 0
            min-idle: 8
    datasource:
        name: test
        url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:${MYSQL_PORT:3306}/test
        username: ----
        password: ----
        # 使用druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        filters: stat
        maxActive: 20
        initialSize: 1
        maxWait: 60000
        minIdle: 1
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: select 'x'
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        maxOpenPreparedStatements: 20
    messages:
        encoding: UTF-8
        basename: i18n/abt_messages
        use-code-as-default-message: true
    mvc:
        view:
          suffix: .html
          prefix: /
    servlet:
        multipart:
          file-size-threshold: 100mb
          max-file-size: 100mb

mybatis:
    basepackage: team.csrj.**.mapper
    mapper-locations: ["classpath*:mapper/**/*.xml","classpath*:com/gitee/sunchenbin/mybatis/actable/mapping/*/*.xml"]
    table:
      auto: create
    model:
      pack: team.csrj
    database:
      type: mysql
logging:
    level:
        team.csrj: debug

management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
      health:
        show-details: ALWAYS
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:7001/eureka/
  instance:
    prefer-ip-address: true
    statusPageUrlPath: /${server.servlet.context-path}/actuator/info
    healthCheckUrlPath: /${server.servlet.context-path}/actuator/health

3.3、主程序

packageteam.csrj.producer;

importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.EnableEurekaClient;
importorg.springframework.context.annotation.ComponentScan;
importorg.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableEurekaClient
@EnableTransactionManagement(proxyTargetClass=true)
@ComponentScan(basePackages={"team.csrj","com.gitee.sunchenbin.mybatis.actable.manager"})
@MapperScan({"team.csrj.**.mapper","com.gitee.sunchenbin.mybatis.actable.dao.**"})
publicclassProducerApplication{

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

3.4、运行结果

<<没错,图还是没有>>

4、eureka 注册过程源码分析

由于不了解为什么客户端的defaultZone一定要加上"/eureka"这个字符串,即使服务端定义的defaultZone没有带"/eureka",客户端也必须带上,从而开始了研究eureka的部分源码。

4.1 eureka-client发送注册信息源码分析

首先通过在DiscoveryClient类中可以发现对应的注册方法 boolean register() throws Throwable,这个方法就是客户端给服务端发送注册信息的入口,我们可以看出他是通过http请求进行注册。

boolean register() throws Throwable {
        logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
        EurekaHttpResponse<Void> httpResponse;
        try {
            httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
        } catch (Exception e) {
            logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
            throw e;
        }
        if (logger.isInfoEnabled()) {
            logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
        }
        return httpResponse.getStatusCode() == 204;
    }

接下来进入核心该方法里面的register(instanceInfo),通过debugger我们发现这个方法是AbstractJerseyEurekaHttpClient该类下面的方法,再进行调试,我们可以看到他是通过将"apps"和客户端的名字的大写组成urlPath,并将serviceUrl(这里的值为客户端配置文件里面的service-url.defaultZone)组合为一个url兵发送到服务端,若服务端返回204,则代表注册成功

<<上传失败的图片>>

<<上传失败的图片>>

4.2、eureka-server接受注册请求源码分析

Eureka-server的rest api是使用javax.ws实现的,及服务注册、下架等功能都是通过对应的Http请求进行执行。以下主要介绍服务注册。

Eureka-server启动过程会初始化对应的配置,其中EurekaServerAutoConfiguration配置类配置了大量的bean,我们主要了解里面的过滤器的配置。ServletContainer里面实现了jersey框架,通过他来实现eurekaServer对外的restFull接口。 从拦截路径可以看出,这些过滤器全部拦截带有“/eureka”字符串的url,我们访问eurekaServer对外的接口都必须通过这些过滤器,与上面对客户端发送的url的对比,我们发现为什么客户端的service-url.defaultZone后面的链接必须带有/eureka,不然无法成功注册,服务端也无法获取客户端的注册请求。

接下来我们在这些客户端里面找有带"/app"路径的拦截器,最终我们发现了ApplicationsResource.java.

 @Bean
    public FilterRegistrationBean jerseyFilterRegistration(Application eurekaJerseyApp) {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new ServletContainer(eurekaJerseyApp));
        bean.setOrder(2147483647);
        bean.setUrlPatterns(Collections.singletonList("/eureka/*"));
        return bean;
    }

我们找到对应的ApplicationsResource类,他主要提供以下三个接口:

/{version}/apps/{appId}

/{version}/apps

/{version}/apps/delta

在eureka里面,这些{version}都是"eureka",通过客户端发送的url,我们可以找到该拦截器里面对应的注册方法

 @Path("{appId}")
    public ApplicationResource getApplicationResource(@PathParam("version") String version, @PathParam("appId") String appId) {
        CurrentRequestVersion.set(Version.toEnum(version));
        return new ApplicationResource(appId, this.serverConfig, this.registry);
    }

从这个代码我们没有找到对应的注册业务逻辑,因此猜测他是将注册的业务逻辑交给了ApplicationResource.class进行。这里面的resource其实和平时的springmvc的控制层类似。

猜你喜欢

转载自blog.csdn.net/AlphonesEric/article/details/89046997