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));

posted @ 2022-04-14 17:58  SpecialSpeculator  阅读(100)  评论(0编辑  收藏  举报