Apoll创建项目分析
1.Apoll创建项目代码分析
POST 请求到/apps
2.controller分析
2.1 Post参数对象AppModel
public class AppModel {
@NotBlank(message = "name cannot be blank")
private String name;
@NotBlank(message = "appId cannot be blank")
@Pattern(
regexp = InputValidator.CLUSTER_NAMESPACE_VALIDATOR,
message = "Invalid AppId format: " + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE
)
private String appId;
@NotBlank(message = "orgId cannot be blank")
private String orgId;
@NotBlank(message = "orgName cannot be blank")
private String orgName;
@NotBlank(message = "ownerName cannot be blank")
private String ownerName;
private Set<String> admins;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
public String getOrgName() {
return orgName;
}
public void setOrgName(String orgName) {
this.orgName = orgName;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public Set<String> getAdmins() {
return admins;
}
public void setAdmins(Set<String> admins) {
this.admins = admins;
}
}
2.2 controller逻辑
@PreAuthorize(value = "@permissionValidator.hasCreateApplicationPermission()")
// 用到了SpringSecurity包里面的判断权限的功能,使用了注解@PreAuthorize,如果没有权限,就直接返回报错
@PostMapping
public App create(@Valid @RequestBody AppModel appModel) {
// 2.3将AppModel 类型对象转换为App对象
App app = transformToApp(appModel);
// 2.4 创建应用信息
App createdApp = appService.createAppInLocal(app);
// 4.1 发布应用创建事件
publisher.publishEvent(new AppCreationEvent(createdApp));
Set<String> admins = appModel.getAdmins();
if (!CollectionUtils.isEmpty(admins)) {
rolePermissionService
.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(createdApp.getAppId()),
admins, userInfoHolder.getUser().getUserId());
}
return createdApp;
}
2.3 transformApp方法
/**
* 将AppModel对象转换为App对象
**/
private App transformToApp(AppModel appModel) {
String appId = appModel.getAppId();
String appName = appModel.getName();
String ownerName = appModel.getOwnerName();
String orgId = appModel.getOrgId();
String orgName = appModel.getOrgName();
return App.builder()
.appId(appId)
.name(appName)
.ownerName(ownerName)
.orgId(orgId)
.orgName(orgName)
.build();
}
2.4 appService.createAppInLocal(app)
@Transactional // 事务注解
public App createAppInLocal(App app) {
String appId = app.getAppId();
App managedApp = appRepository.findByAppId(appId); // 通过数据库中的App表找到应用名字id为appId的记录
if (managedApp != null) {
// 查重校验
throw new BadRequestException(String.format("App already exists. AppId = %s", appId));
}
// 判断应用的所属人员,目前系统中是否还存在
UserInfo owner = userService.findByUserId(app.getOwnerName());
if (owner == null) {
throw new BadRequestException("Application's owner not exist.");
}
app.setOwnerEmail(owner.getEmail());
// 获取当前用户
String operator = userInfoHolder.getUser().getUserId();
// 补齐应用的创建人,修改人
app.setDataChangeCreatedBy(operator);
app.setDataChangeLastModifiedBy(operator);
App createdApp = appRepository.save(app); // 数据落App表
// 2.5 创建应用关联的默认namespace
appNamespaceService.createDefaultAppNamespace(appId);
// 2.6 初始化应用的角色信息
roleInitializationService.initAppRoles(createdApp);
// 2.7 发布日志事件,记录日志
Tracer.logEvent(TracerEventType.CREATE_APP, appId);
return createdApp;
}
2.5 创建应用关联的默认namespace
appNamespaceService.createDefaultAppNamespace(appId)
@Transactional
public void createDefaultAppNamespace(String appId) {
if (!isAppNamespaceNameUnique(appId, ConfigConsts.NAMESPACE_APPLICATION)) {
throw new BadRequestException(String.format("App already has application namespace. AppId = %s", appId));
}
// 对应了AppNamespace表一条记录,里面关联了应用Id
AppNamespace appNs = new AppNamespace();
appNs.setAppId(appId);
appNs.setName(ConfigConsts.NAMESPACE_APPLICATION);
appNs.setComment("default app namespace");
appNs.setFormat(ConfigFileFormat.Properties.getValue());
String userId = userInfoHolder.getUser().getUserId();
appNs.setDataChangeCreatedBy(userId);
appNs.setDataChangeLastModifiedBy(userId);
appNamespaceRepository.save(appNs);
}
2.6 初始化应用的角色信息
roleInitializationService.initAppRoles(createdApp);
@Transactional
public void initAppRoles(App app) {
String appId = app.getAppId();
// 创建角色名字,以Master+AppId为主
String appMasterRoleName = RoleUtils.buildAppMasterRoleName(appId);
//has created before,判断一下这个角色的名字是否在数据库中已存在
if (rolePermissionService.findRoleByRoleName(appMasterRoleName) != null) {
return;
}
// 获取应用的创建人信息
String operator = app.getDataChangeCreatedBy();
// 3.1 create app permissions,创建应用相关的角色及相关权限逻辑
createAppMasterRole(appId, operator);
// 3.2 create manageAppMaster permission
createManageAppMasterRole(appId, operator);
// 3.3 创建角色与用户的关系
rolePermissionService
.assignRoleToUsers(RoleUtils.buildAppMasterRoleName(appId), Sets.newHashSet(app.getOwnerName()),
operator);
initNamespaceRoles(appId, ConfigConsts.NAMESPACE_APPLICATION, operator);
initNamespaceEnvRoles(appId, ConfigConsts.NAMESPACE_APPLICATION, operator);
//assign modify、release namespace role to user
rolePermissionService.assignRoleToUsers(
RoleUtils.buildNamespaceRoleName(appId, ConfigConsts.NAMESPACE_APPLICATION, RoleType.MODIFY_NAMESPACE),
Sets.newHashSet(operator), operator);
rolePermissionService.assignRoleToUsers(
RoleUtils.buildNamespaceRoleName(appId, ConfigConsts.NAMESPACE_APPLICATION, RoleType.RELEASE_NAMESPACE),
Sets.newHashSet(operator), operator);
}
2.7 发布日志事件,记录日志
public static void logEvent(String type, String name) {
try {
getProducer().logEvent(type, name);
} catch (Throwable ex) {
logger.warn("Failed to log event for type: {}, name: {}", type, name, ex);
}
}
private static MessageProducer getProducer() {
try {
if (producerManager == null) {
synchronized (lock) {
if (producerManager == null) {
producerManager = ServiceBootstrap.loadFirst(MessageProducerManager.class);
}
}
}
} catch (Throwable ex) {
logger.error(
"Failed to initialize message producer manager, use null message producer manager.", ex);
producerManager = NULL_MESSAGE_PRODUCER_MANAGER;
}
return producerManager.getProducer();
}
// 对应了有一些logEvent的实现类CatMessageProducer,里面执行了某些方法,反射
@Override
public void logEvent(String type, String name) {
try {
LOG_EVENT_WITH_TYPE_AND_NAME.invoke(null, type, name);
} catch (Throwable ex) {
throw new IllegalStateException(ex);
}
}
3.角色相关的特殊说明
3.1 创建masterRole角色
createAppMasterRole(appId, operator)
private void createAppMasterRole(String appId, String operator) {
Set<Permission> appPermissions =
Stream.of(PermissionType.CREATE_CLUSTER, PermissionType.CREATE_NAMESPACE, PermissionType.ASSIGN_ROLE)
.map(permissionType -> createPermission(appId, permissionType, operator)).collect(Collectors.toSet());
Set<Permission> createdAppPermissions = rolePermissionService.createPermissions(appPermissions); // 权限表Permission落库了(权限表里有权限名字及应用的名字关系)
Set<Long>
appPermissionIds =
createdAppPermissions.stream().map(BaseEntity::getId).collect(Collectors.toSet());
//create app master role,这个是角色表Role的数据
Role appMasterRole = createRole(RoleUtils.buildAppMasterRoleName(appId), operator);
// 角色和权限的绑定关系落库
rolePermissionService.createRoleWithPermissions(appMasterRole, appPermissionIds);
}
private Permission createPermission(String targetId, String permissionType, String operator) {
Permission permission = new Permission();
permission.setPermissionType(permissionType);
permission.setTargetId(targetId);
permission.setDataChangeCreatedBy(operator);
permission.setDataChangeLastModifiedBy(operator);
return permission;
}
/**
* rolePermissionService.createPermissions
**/
@Transactional
public Set<Permission> createPermissions(Set<Permission> permissions) {
Multimap<String, String> targetIdPermissionTypes = HashMultimap.create();
for (Permission permission : permissions) {
targetIdPermissionTypes.put(permission.getTargetId(), permission.getPermissionType());
}
for (String targetId : targetIdPermissionTypes.keySet()) {
Collection<String> permissionTypes = targetIdPermissionTypes.get(targetId);
List<Permission> current =
permissionRepository.findByPermissionTypeInAndTargetId(permissionTypes, targetId);
Preconditions.checkState(CollectionUtils.isEmpty(current),
"Permission with permissionType %s targetId %s already exists!", permissionTypes,
targetId);
}
Iterable<Permission> results = permissionRepository.saveAll(permissions);
return StreamSupport.stream(results.spliterator(), false).collect(Collectors.toSet());
}
看下数据库中的结构
Permission表
MariaDB [ApolloPortalDB]> select * from Permission;
+----+------------------+------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| Id | PermissionType | TargetId | IsDeleted | DataChange_CreatedBy | DataChange_CreatedTime | DataChange_LastModifiedBy | DataChange_LastTime |
+----+------------------+------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| 1 | CreateNamespace | dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 2 | CreateCluster | dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 3 | AssignRole | dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 4 | ManageAppMaster | dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 5 | ModifyNamespace | dubbo-demo-service+application | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 6 | ReleaseNamespace | dubbo-demo-service+application | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 7 | ModifyNamespace | dubbo-demo-service+application+DEV | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 8 | ReleaseNamespace | dubbo-demo-service+application+DEV | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
+----+------------------+------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
8 rows in set (0.001 sec)
Rule角色表
MariaDB [ApolloPortalDB]> select * from Role;
+----+-----------------------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| Id | RoleName | IsDeleted | DataChange_CreatedBy | DataChange_CreatedTime | DataChange_LastModifiedBy | DataChange_LastTime |
+----+-----------------------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| 1 | Master+dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 2 | ManageAppMaster+dubbo-demo-service | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 3 | ModifyNamespace+dubbo-demo-service+application | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 4 | ReleaseNamespace+dubbo-demo-service+application | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 5 | ModifyNamespace+dubbo-demo-service+application+DEV | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 6 | ReleaseNamespace+dubbo-demo-service+application+DEV | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
+----+-----------------------------------------------------+-----------+----------------------+------------------------+---------------------------+---------------------+
6 rows in set (0.001 sec)
Rule角色和权限Permission的关系表
MariaDB [ApolloPortalDB]> select * from RolePermission;
+----+--------+--------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| Id | RoleId | PermissionId | IsDeleted | DataChange_CreatedBy | DataChange_CreatedTime | DataChange_LastModifiedBy | DataChange_LastTime |
+----+--------+--------------+-----------+----------------------+------------------------+---------------------------+---------------------+
| 1 | 1 | 1 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 2 | 1 | 2 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 3 | 1 | 3 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 4 | 2 | 4 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 5 | 3 | 5 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 6 | 4 | 6 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 7 | 5 | 7 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 8 | 6 | 8 | | apollo | 2022-04-13 20:07:39 | apollo | 2022-04-13 20:07:39 |
| 9 | 7 | 9 | | apollo | 2022-04-14 17:39:38 | apollo | 2022-04-14 17:49:31 |
| 10 | 7 | 10 | | apollo | 2022-04-14 17:39:38 | apollo | 2022-04-14 17:49:31 |
| 11 | 7 | 11 | | apollo | 2022-04-14 17:39:38 | apollo | 2022-04-14 17:49:31 |
| 12 | 8 | 12 | | apollo | 2022-04-14 17:39:38 | apollo | 2022-04-14 17:49:31 |
| 13 | 9 | 13 | | apollo | 2022-04-14 17:39:39 | apollo | 2022-04-14 17:49:31 |
| 14 | 10 | 14 | | apollo | 2022-04-14 17:39:39 | apollo | 2022-04-14 17:49:31 |
| 15 | 11 | 15 | | apollo | 2022-04-14 17:39:39 | apollo | 2022-04-14 17:49:31 |
| 16 | 12 | 16 | | apollo | 2022-04-14 17:39:39 | apollo | 2022-04-14 17:49:31 |
| 17 | 13 | 17 | | apollo | 2022-04-14 17:50:41 | apollo | 2022-04-14 17:51:37 |
| 18 | 13 | 18 | | apollo | 2022-04-14 17:50:41 | apollo | 2022-04-14 17:51:37 |
| 19 | 13 | 19 | | apollo | 2022-04-14 17:50:41 | apollo | 2022-04-14 17:51:37 |
| 20 | 14 | 20 | | apollo | 2022-04-14 17:50:41 | apollo | 2022-04-14 17:51:37 |
| 21 | 15 | 21 | | apollo | 2022-04-14 17:50:41 | apollo | 2022-04-14 17:51:37 |
| 22 | 16 | 22 | | apollo | 2022-04-14 17:50:42 | apollo | 2022-04-14 17:51:37 |
| 23 | 17 | 23 | | apollo | 2022-04-14 17:50:43 | apollo | 2022-04-14 17:51:37 |
| 24 | 18 | 24 | | apollo | 2022-04-14 17:50:43 | apollo | 2022-04-14 17:51:37 |
| 25 | 19 | 25 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 26 | 19 | 26 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 27 | 19 | 27 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 28 | 20 | 28 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 29 | 21 | 29 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 30 | 22 | 30 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 31 | 23 | 31 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
| 32 | 24 | 32 | | apollo | 2022-04-14 17:52:04 | apollo | 2022-04-14 17:52:04 |
+----+--------+--------------+-----------+----------------------+------------------------+---------------------------+---------------------+
32 rows in set (0.000 sec)
3.2 创建管理MasterRole
@Transactional
private void createManageAppMasterRole(String appId, String operator) {
Permission permission = createPermission(appId, PermissionType.MANAGE_APP_MASTER, operator);
rolePermissionService.createPermission(permission);
Role role = createRole(RoleUtils.buildAppRoleName(appId, PermissionType.MANAGE_APP_MASTER), operator);
Set<Long> permissionIds = new HashSet<>();
permissionIds.add(permission.getId());
rolePermissionService.createRoleWithPermissions(role, permissionIds);
}
3.3 创建角色与用户的关系
@Transactional
public Set<String> assignRoleToUsers(String roleName, Set<String> userIds,
String operatorUserId) {
Role role = findRoleByRoleName(roleName);
Preconditions.checkState(role != null, "Role %s doesn't exist!", roleName);
List<UserRole> existedUserRoles =
userRoleRepository.findByUserIdInAndRoleId(userIds, role.getId());
Set<String> existedUserIds =
existedUserRoles.stream().map(UserRole::getUserId).collect(Collectors.toSet());
Set<String> toAssignUserIds = Sets.difference(userIds, existedUserIds);
Iterable<UserRole> toCreate = toAssignUserIds.stream().map(userId -> {
UserRole userRole = new UserRole();
userRole.setRoleId(role.getId());
userRole.setUserId(userId);
userRole.setDataChangeCreatedBy(operatorUserId);
userRole.setDataChangeLastModifiedBy(operatorUserId);
return userRole;
}).collect(Collectors.toList());
userRoleRepository.saveAll(toCreate);
return toAssignUserIds;
}
4. 事件处理
4.1 发布事件
SpringContext的事件,
publisher.publishEvent(new AppCreationEvent(createdApp));
原创:做时间的朋友