【知其然,知其所以然】配置中心 Apollo源码剖析

第2章 Apollo源码剖析

能力目标

  • 能够基于Git导入Apollo源码
  • 能够基于IDEA实现DEBUG分析APP创建
  • 掌握Namespace创建过程
  • 掌握Item创建过程
  • 掌握灰度发布创建过程

1:namespace创建、灰度发布配置、Item创建作为自学

2:客户端剖析

​ 通信->Http、轮询机制

​ 配置文件优先级、缓存、关联关系

​ 刷新机制【注解解析】

1 Apollo源码搭建

在上一章我们已经学习了Apollo项目实战,为了更进一步学习Apollo、掌握Apollo工作原理,我们开始学习Apollo源码,所以我们先搭建Apollo源码环境。

1.1 源码下载

我们从github上 https://github.com/ctripcorp/apollo 下载源码,下载后的源码如下:

file

版本切换至v1.7.1(课程中使用的是1.7.0),如下操作:

file

1.2 导入数据库

在项目根路径下有scripts/sql目录,下面有2个sql脚本,我们将该脚本导入到数据库中。

file

如下图,在本地mysql上执行这两个脚本:

file

1.3 apollo-assembly启动服务

我们启动Apollo服务,需要同时启动configservice、adminservice,如果手动启动比较慢,Apollo帮我们封装了一个工程apollo-assembly,可以基于该工程同时启动 apollo-adminserviceapollo-configservice 项目。

修改apollo-configservice的核心配置文件bootstrap.yml添加Eureka不注册Eureka数据也不获取Eureka数据,配置如下:

file

完整代码如下:

eureka:
  instance:
    hostname: ${hostname:localhost}
    preferIpAddress: true
    status-page-url-path: /info
    health-check-url-path: /health
  server:
    peerEurekaNodesUpdateIntervalMs: 60000
    enableSelfPreservation: false
  client:
    serviceUrl:
      # This setting will be overridden by eureka.service.url setting from ApolloConfigDB.ServerConfig or System Property
      # see com.ctrip.framework.apollo.biz.eureka.ApolloEurekaClientConfig
      defaultZone: http://${eureka.instance.hostname}:8080/eureka/
    healthcheck:
      enabled: true
    eurekaServiceUrlPollIntervalSeconds: 60
    fetch-registry: false
    register-with-eureka: false

我们先配置该工程,如下图:

file

这里的VM optins:

-Dapollo_profile=github
-Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloConfigDB?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
-Dspring.datasource.username=root
-Dspring.datasource.password=123456
-Dlogging.file=D:/project/xc-apollo/apollo-assembly.log

参数Program arguments中的两个参数分别表示启动configserviceadminservice服务。

启动完成后,我们请求Eureka http://localhost:8080/

file

PortalService启动

apollo-portal工程需要单独启动,启动的时候我们也需要配置密码和日志输出文件,如下图:

file

VM options配置如下:

-Dapollo_profile=github,auth
-Ddev_meta=http://localhost:8080/
-Dserver.port=8070
-Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloPortalDB?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
-Dspring.datasource.username=root
-Dspring.datasource.password=123456
-Dlogging.file=D:/project/xc-apollo/apollo-portal.log

启动完成后,我们接下来访问控制台 http://localhost:8070 效果如下:

file

1.4 服务测试

我们可以先创建一个项目并且app.id=100004458,如下图:

file

file 在该项目的application.properties中添加一个username参数,如下图:

file

Apollo提供了内置的测试服务,该服务会访问Apollo服务app.id=100004458的项目,我们可以在该工程启动时配置VM options参数指定Apollo注册中心地址,如下图:

file

VM options参数配置如下:

-Denv=dev
-Ddev_meta=http://localhost:8080

启动程序,我们输入username回车,可以看到对应数据,如下输出结果:

Apollo Config Demo. Please input key to get the value. Input quit to exit.
> username
> [apollo-demo][main] INFO  [com.ctrip.framework.apollo.demo.api.SimpleApolloConfigDemo] Loading key : username with value: 张三

2 Portal创建APP

Apollo创建App的过程如果基于控制台操作是很简单的,但是Apollo是如何实现的呢,我们接下来进行相关源码剖析。

file

创建APP的流程如上图:

1:用户在后台执行创建app,会将请求发送到Portal Service
2:Portal Service将数据保存到Portal DB中
3:Portal Service同时将数据同步到Admin Service中,这个过程是异步的
4:Admin Service将数据保存到Config DB中

2.1 创建APP

创建APP由Portal Service执行,我们从它的JavaBean、Controller、Service、Dao一步一步分析。

2.1.1 实体Bean

1)Table

APP对应的表结构如下:

CREATE TABLE `App` (
  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
  `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
  `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
  `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
  `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
  `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
  `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀',
  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
  PRIMARY KEY (`Id`),
  KEY `AppId` (`AppId`(191)),
  KEY `DataChange_LastTime` (`DataChange_LastTime`),
  KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='应用表';

2)App(Bean)

apollo-common 项目中, com.ctrip.framework.apollo.common.entity.App ,继承 BaseEntity 抽象类,应用信息实体。代码如下:

@Entity
@Table(name = "App")
@SQLDelete(sql = "Update App set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class App extends BaseEntity {

  /**
   * App名字
   */
  @NotBlank(message = "Name cannot be blank")
  @Column(name = "Name", nullable = false)
  private String name;

  /**
   * App.id
   */
  @NotBlank(message = "AppId cannot be blank")
  @Pattern(
      regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
      message = InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
  )
  @Column(name = "AppId", nullable = false)
  private String appId;

  /**
   * 部门编号
   */
  @Column(name = "OrgId", nullable = false)
  private String orgId;

  /**
   * 部门名
   */
  @Column(name = "OrgName", nullable = false)
  private String orgName;

  /***
   * 拥有人名
   * 例如在 Portal 系统中,使用系统的管理员账号,即 UserPO.username 字段
   */
  @NotBlank(message = "OwnerName cannot be blank")
  @Column(name = "OwnerName", nullable = false)
  private String ownerName;

  /***
   * 拥有人邮箱
   */
  @NotBlank(message = "OwnerEmail cannot be blank")
  @Column(name = "OwnerEmail", nullable = false)
  private String ownerEmail;
  //...get set 略

}
  • ORM 选用 Hibernate 框架。
  • @SQLDelete(...) + @Where(...) 注解,配合 BaseEntity.extends 字段,实现 App 的逻辑删除
  • 字段比较简单。

3)BaseEntity(Bean)

com.ctrip.framework.apollo.common.entity.BaseEntity ,是基础实体抽象类。代码如下:

@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {

  /**
   * 编号
   */
  @
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值