在之前那章 midwayjs路由实现那章 我们看到过这样的代码

  1. /**
  2. * save data to class
  3. * @param decoratorNameKey
  4. * @param data
  5. * @param target
  6. * @param mergeIfExist
  7. */
  8. export function saveClassMetadata(
  9. decoratorNameKey: ObjectIdentifier,
  10. data: any,
  11. target: any,
  12. mergeIfExist?: boolean
  13. ) {
  14. if (mergeIfExist && typeof data === 'object') {
  15. const originData = manager.getMetadata(decoratorNameKey, target);
  16. if (!originData) {
  17. return manager.saveMetadata(decoratorNameKey, data, target);
  18. }
  19. if (Array.isArray(originData)) {
  20. return manager.saveMetadata(
  21. decoratorNameKey,
  22. originData.concat(data),
  23. target
  24. );
  25. } else {
  26. return manager.saveMetadata(
  27. decoratorNameKey,
  28. Object.assign(originData, data),
  29. target
  30. );
  31. }
  32. } else {
  33. return manager.saveMetadata(decoratorNameKey, data, target);
  34. }
  35. }

其中 manager 就是我们最开始所描述的容器 下面阶段来介绍下 这个 manager

1. saveMetadata

这个看方法名 理解起来也不难 就是 元数据的存储 接下来就是解析下 源码的执行过程

  1. export class DecoratorManager extends Map implements IModuleStore {
  2. /**
  3. * the key for method meta data store in method
  4. */
  5. injectMethodKeyPrefix = 'INJECTION_METHOD_META_DATA';
  6. injectClassKeyPrefix = 'INJECTION_CLASS_META_DATA'
  7. static getDecoratorMethodKey(decoratorNameKey: ObjectIdentifier) {
  8. return decoratorNameKey.toString() + '_METHOD';
  9. }
  10. static getDecoratorMethod(
  11. decoratorNameKey: ObjectIdentifier,
  12. methodKey: ObjectIdentifier
  13. ) {
  14. return (
  15. DecoratorManager.getDecoratorMethodKey(decoratorNameKey) +
  16. '_' +
  17. methodKey.toString()
  18. );
  19. }
  20. // 静态方法 存储元数据
  21. static saveMetadata(
  22. metaKey: string,
  23. target: any,
  24. dataKey: string,
  25. data: any
  26. ) {
  27. // filter Object.create(null)
  28. if (typeof target === 'object' && target.constructor) {
  29. target = target.constructor;
  30. }
  31. let m: Map<string, any>;
  32. // 如果 target 对应的 元key 存在 元数据
  33. if (Reflect.hasOwnMetadata(metaKey, target)) {
  34. // m 等于用户存储的元数据
  35. m = Reflect.getMetadata(metaKey, target);
  36. } else {
  37. // 否则 初始化一个新的 map
  38. m = new Map<string, any>();
  39. }
  40. // 存储新的 属性值对应的数据
  41. m.set(dataKey, data);
  42. Reflect.defineMetadata(metaKey, m, target);
  43. }
  44. /**
  45. * save meta data to class or property
  46. * @param decoratorNameKey the alias name for decorator
  47. * @param data the data you want to store
  48. * @param target target class
  49. * @param propertyName
  50. */
  51. // 存储元数据
  52. saveMetadata(
  53. decoratorNameKey: ObjectIdentifier,
  54. data,
  55. target,
  56. propertyName?
  57. ) {
  58. if (propertyName) {
  59. // 假如 用户输入了 propertyName
  60. // saveMetadata('decoratorNameKey', {}, target, 'propertyKey')
  61. const dataKey = DecoratorManager.getDecoratorMethod(
  62. decoratorNameKey,
  63. propertyName
  64. );
  65. // dataKey 此时取到的值 为 'decoratorNameKey_METHOD_propertyKey'
  66. DecoratorManager.saveMetadata(
  67. this.injectMethodKeyPrefix,
  68. target,
  69. dataKey,
  70. data
  71. );
  72. } else {
  73. // 如果用户没有输入 propertyName
  74. // saveMetadata('decoratorNameKey', {}, target)
  75. const dataKey = DecoratorManager.getDecoratorClassKey(decoratorNameKey);
  76. // dataKey 此时取到的值 为 'decoratorNameKey_METHOD'
  77. DecoratorManager.saveMetadata(
  78. this.injectClassKeyPrefix,
  79. target,
  80. dataKey,
  81. data
  82. );
  83. }
  84. }
  85. }

执行流程如下

  1. 首先 我们根据 有没有 propertyName 入参 来生成一个 dataKey
  2. 执行 DecoratorManager的静态方法 saveMetadata 来存储元数据

如果 没有 输入的 propertyName 的话 说明存储 的一个类级别的元数据 用 INJECTION_CLASS_META_DATA 所为 key
否则 的话 用 INJECTION_METHOD_META_DATA

同时看静态方法 也知道 这两个key 下存的值是 Map 的格式 而 Map 的key 就是我们刚才得出来的 dataKey

2. getMetadata

有set的话 就有get 那么继续看代码了

  1. export class DecoratorManager extends Map implements IModuleStore {
  2. // 静态方法 获取元数据
  3. static getMetadata(metaKey: string, target: any, dataKey?: string) {
  4. // filter Object.create(null)
  5. if (typeof target === 'object' && target.constructor) {
  6. target = target.constructor;
  7. }
  8. let m: Map<string, any>;
  9. if (!Reflect.hasOwnMetadata(metaKey, target)) {
  10. m = new Map<string, any>();
  11. Reflect.defineMetadata(metaKey, m, target);
  12. } else {
  13. m = Reflect.getMetadata(metaKey, target);
  14. }
  15. if (!dataKey) {
  16. return m;
  17. }
  18. return m.get(dataKey);
  19. }
  20. /**
  21. * get single data from class or property
  22. * @param decoratorNameKey
  23. * @param target
  24. * @param propertyName
  25. */
  26. getMetadata(decoratorNameKey: ObjectIdentifier, target, propertyName?) {
  27. if (propertyName) {
  28. const dataKey = DecoratorManager.getDecoratorMethod(
  29. decoratorNameKey,
  30. propertyName
  31. );
  32. return DecoratorManager.getMetadata(
  33. this.injectMethodKeyPrefix,
  34. target,
  35. dataKey
  36. );
  37. } else {
  38. const dataKey = `${DecoratorManager.getDecoratorClassKey(
  39. decoratorNameKey
  40. )}`;
  41. return DecoratorManager.getMetadata(
  42. this.injectClassKeyPrefix,
  43. target,
  44. dataKey
  45. );
  46. }
  47. }
  48. }