最近公司项目用到了Apollo,花了几天功夫把Apollo的官方文档过了一遍,不得不说写的非常详细。基本的使用,已经简单的原理都介绍的明明白白的。
在文档上有这么句话:据说Apollo非常适合作为初学者第一个通读源码学习的分布式中间件产品
那么就开始吧。
这里我主要为了记录一些在阅读Apollo源码时所学习到的一些开发技巧,方便自己回顾。
我是一边参考:Apollo源码解析,一边自己阅读源码,有很多东西也是从那边粘过来的。
首先我们看一下apollo-common
模块中的com.ctrip.framework.apollo.common.entity.App
:
@Entity
@Table(name = "App")
@SQLDelete(sql = "Update App set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class App extends BaseEntity {
@NotBlank(message = "Name cannot be blank")
@Column(name = "Name", nullable = false)
private String name;
......
public static class Builder {
public Builder() {
}
private App app = new App();
public Builder name(String name) {
app.setName(name);
return this;
}
......
public App build() {
return app;
}
}
public static Builder builder() {
return new Builder();
}
}
顺着这条线,看一下com.ctrip.framework.apollo.common.entity.BaseEntity
:
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id")
private long id;
@Column(name = "IsDeleted", columnDefinition = "Bit default '0'")
protected boolean isDeleted = false;
@Column(name = "DataChange_CreatedBy", nullable = false)
private String dataChangeCreatedBy;
@Column(name = "DataChange_CreatedTime", nullable = false)
private Date dataChangeCreatedTime;
@Column(name = "DataChange_LastModifiedBy")
private String dataChangeLastModifiedBy;
@Column(name = "DataChange_LastTime")
private Date dataChangeLastModifiedTime;
......
@PrePersist
protected void prePersist() {
if (this.dataChangeCreatedTime == null) dataChangeCreatedTime = new Date();
if (this.dataChangeLastModifiedTime == null) dataChangeLastModifiedTime = new Date();
}
@PreUpdate
protected void preUpdate() {
this.dataChangeLastModifiedTime = new Date();
}
@PreRemove
protected void preRemove() {
this.dataChangeLastModifiedTime = new Date();
}
接下来我们追一下创建App的流程,apollo-portal
模块下的com.ctrip.framework.apollo.portal.controller.AppController
:
@RestController
@RequestMapping("/apps")
public class AppController {
private final AppService appService;
private final ApplicationEventPublisher publisher;
private final RolePermissionService rolePermissionService;
@PostMapping
public App create(@Valid @RequestBody AppModel appModel) {
App app = transformToApp(appModel);
App createdApp = appService.createAppInLocal(app);
publisher.publishEvent(new AppCreationEvent(createdApp));
Set admins = appModel.getAdmins();
if (!CollectionUtils.isEmpty(admins)) {
rolePermissionService
.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(createdApp.getAppId()),
admins, userInfoHolder.getUser().getUserId());
}
return createdApp;
}
}
时间的监听者在这com.ctrip.framework.apollo.portal.listener.CreationListener
:
@EventListener
public void onAppCreationEvent(AppCreationEvent event) {
AppDTO appDTO = BeanUtils.transform(AppDTO.class, event.getApp());
List envs = portalSettings.getActiveEnvs();
for (Env env : envs) {
try {
appAPI.createApp(env, appDTO);
} catch (Throwable e) {
logger.error("Create app failed. appId = {}, env = {})", appDTO.getAppId(), env, e);
Tracer.logError(String.format("Create app failed. appId = %s, env = %s", appDTO.getAppId(), env), e);
}
}
}
项目中大量的使用了各种各样的实体对象,这里总结一点我自己的理解:
同样也是追创建cluster的流程,先来看一下apollo-biz
模块下的com.ctrip.framework.apollo.biz.entity.Cluster
:
@Entity
@Table(name = "Cluster")
@SQLDelete(sql = "Update Cluster set isDeleted = 1 where id = ?")
@Where(clause = "isDeleted = 0")
public class Cluster extends BaseEntity implements Comparable {
@Column(name = "Name", nullable = false)
private String name;
@Column(name = "AppId", nullable = false)
private String appId;
@Column(name = "ParentClusterId", nullable = false)
private long parentClusterId;
......
}
再看一下apollo-portal
模块下的com.ctrip.framework.apollo.portal.controller.ClusterController
:
@RestController
public class ClusterController {
private final ClusterService clusterService;
private final UserInfoHolder userInfoHolder;
@PreAuthorize(value = "@permissionValidator.hasCreateClusterPermission(#appId)")
@PostMapping(value = "apps/{appId}/envs/{env}/clusters")
public ClusterDTO createCluster(@PathVariable String appId, @PathVariable String env,
@Valid @RequestBody ClusterDTO cluster) {
String operator = userInfoHolder.getUser().getUserId();
cluster.setDataChangeLastModifiedBy(operator);
cluster.setDataChangeCreatedBy(operator);
return clusterService.createCluster(Env.valueOf(env), cluster);
}
......
}
然后这里是apollo-adminservice
模块中保存cluster的方法:
@Transactional
public Cluster saveWithoutInstanceOfAppNamespaces(Cluster entity) {
if (!isClusterNameUnique(entity.getAppId(), entity.getName())) {
throw new BadRequestException("cluster not unique");
}
entity.setId(0);//protection
Cluster cluster = clusterRepository.save(entity);
auditService.audit(Cluster.class.getSimpleName(), cluster.getId(), Audit.OP.INSERT,
cluster.getDataChangeCreatedBy());
return cluster;
}
entity.setId(0);
这里给对象id设置为0是防止被注入id导致更新对象