定义切面注解

定义切面注解AiPassiveMsg

  1. package com.iwhalecloud.aiFactory.common.aspect;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. /**
  8. * @description:
  9. * @author: hasee
  10. * @create: 2022-04-24 18:16
  11. **/
  12. @Target(ElementType.METHOD)
  13. @Retention(RetentionPolicy.RUNTIME)
  14. @Documented
  15. public @interface AiPassiveMsg {
  16. /** 场景类型,具体场景和环节使用对应的类型前缀,用点拼接.系统=sys,安全=security,审核=audit.xxx.xxxx; */
  17. String sceneType() default "";
  18. /** 替换参数json字符串 */
  19. String param() default "";
  20. /** 用户id ["1001","1002","1003"] */
  21. String[] users() default {};
  22. }

定义切面类

  1. package com.iwhalecloud.aiFactory.aspect;
  2. import com.iwhalecloud.aiFactory.aspect.msghandler.AiPassiveMsgHandler;
  3. import com.iwhalecloud.aiFactory.aspect.msghandler.MsgHandlerContext;
  4. import com.iwhalecloud.aiFactory.auth.CurrentUserHolder;
  5. import com.iwhalecloud.aiFactory.common.aspect.AiPassiveMsg;
  6. import com.iwhalecloud.aiFactory.common.util.LoggerUtil;
  7. import com.iwhalecloud.aiFactory.system.service.api.dto.response.UserInfoDto;
  8. import org.aspectj.lang.JoinPoint;
  9. import org.aspectj.lang.annotation.AfterReturning;
  10. import org.aspectj.lang.annotation.Aspect;
  11. import org.aspectj.lang.annotation.Pointcut;
  12. import org.aspectj.lang.reflect.MethodSignature;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.stereotype.Component;
  15. import java.io.IOException;
  16. import java.lang.reflect.Method;
  17. import java.util.HashMap;
  18. /**
  19. * @author hasee
  20. * @Description 消息中心埋点
  21. * @since 2022/3/14 14:30
  22. */
  23. @Aspect
  24. @Component
  25. public class AiPassiveMsgAspect {
  26. @Autowired
  27. MsgHandlerContext msgHandlerContext;
  28. @Pointcut("@annotation(com.iwhalecloud.aiFactory.common.aspect.AiPassiveMsg)")
  29. public void cut() {
  30. LoggerUtil.info("被动消息切面切入");
  31. }
  32. @AfterReturning("cut()")
  33. public void addAiInformation(JoinPoint joinPoint) throws IOException {
  34. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  35. Method method = methodSignature.getMethod();
  36. // 获取注解参数
  37. AiPassiveMsg annotation = method.getAnnotation(AiPassiveMsg.class);
  38. // 通过枚举值或者方法的调用
  39. String sceneType = annotation.sceneType();
  40. String[] users = annotation.users();
  41. UserInfoDto currentUser = CurrentUserHolder.getCurrentUser();
  42. Object[] joinPointArgs = joinPoint.getArgs();
  43. AiPassiveMsgHandler instance = msgHandlerContext.getInstance(sceneType);
  44. HashMap<String, Object> map = new HashMap<>();
  45. map.put("sceneType",sceneType);
  46. map.put("currentUser",currentUser);
  47. map.put("joinPointArgs",joinPointArgs);
  48. instance.handle(map);
  49. }
  50. }

其中@AfterReturning("cut()")执行切入点动作
但是MsgHandlerContext是什么?

定义业务类

业务方法applyPublish

  1. @Override
  2. @Transactional(value = "inferenceTransactionManager", rollbackFor = Exception.class)
  3. @AiPassiveMsg(sceneType = "audit.serviceVersion.publish")
  4. public void applyPublish(AirServicePublishBeRequest request) {
  5. ...
  6. }

业务方法approvePublish

  1. @Override
  2. @Transactional("inferenceTransactionManager")
  3. @AiPassiveMsg(sceneType = "audit.serviceVersion.publish.audit")
  4. public void approvePublish(AirInferenceApprovedInfo request) {

策略模式

打在业务方法上的@AiPassiveMsg(sceneType = "audit.serviceVersion.publish") 或者 @AiPassiveMsg(sceneType = "audit.serviceVersion.publish.audit")我们应该做出怎么样的处理呢?这里就要定义抽象处理器Handler以及它的子类具体实现类, 即 AiPassiveMsgHandlerPublishServiceVersionMsgHandlerApprovePublishServiceVersionMsgHandler

AiPassiveMsgHandler

image.png
AiPassiveMsgHandler

  1. package com.iwhalecloud.aiFactory.aspect.msghandler;
  2. import java.io.IOException;
  3. import java.util.Map;
  4. /**
  5. * @description:
  6. * @author: hasee
  7. * @create: 2022-04-25 09:15
  8. **/
  9. public abstract class AiPassiveMsgHandler {
  10. public abstract Map<String, Object> handle(Map<String, Object> params) throws IOException;
  11. }

PublishServiceVersionMsgHandler

  1. package com.iwhalecloud.aiFactory.aspect.msghandler.process;
  2. import com.iwhalecloud.aiFactory.aiResource.aimessage.MsgTmplService;
  3. import com.iwhalecloud.aiFactory.aspect.msghandler.AiPassiveMsgHandler;
  4. import com.iwhalecloud.aiFactory.aspect.msghandler.PassiveMsgHandlerType;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Component;
  7. import java.io.IOException;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. /**
  11. * @description:
  12. * @author: hasee
  13. * @create: 2022-04-25 09:23
  14. **/
  15. @Component
  16. @PassiveMsgHandlerType("audit.serviceVersion.publish")
  17. public class PublishServiceVersionMsgHandler extends AiPassiveMsgHandler {
  18. @Autowired
  19. MsgTmplService msgTmplService;
  20. @Override
  21. public Map<String, Object> handle(Map<String, Object> params) {
  22. try {
  23. msgTmplService.serviceVersionPublishAspect(params);
  24. }
  25. catch (RuntimeException e) {
  26. }
  27. return new HashMap<>();
  28. }
  29. }

ApprovePublishServiceVersionMsgHandler

  1. package com.iwhalecloud.aiFactory.aspect.msghandler.process;
  2. import com.iwhalecloud.aiFactory.aiResource.aimessage.MsgTmplService;
  3. import com.iwhalecloud.aiFactory.aspect.msghandler.AiPassiveMsgHandler;
  4. import com.iwhalecloud.aiFactory.aspect.msghandler.PassiveMsgHandlerType;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Component;
  7. import java.io.IOException;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. /**
  11. * @description:
  12. * @author: hasee
  13. * @create: 2022-04-25 09:23
  14. **/
  15. @Component
  16. @PassiveMsgHandlerType("audit.serviceVersion.publish.audit")
  17. public class ApprovePublishServiceVersionMsgHandler extends AiPassiveMsgHandler {
  18. @Autowired
  19. MsgTmplService msgTmplService;
  20. @Override
  21. public Map<String, Object> handle(Map<String, Object> params) {
  22. try {
  23. msgTmplService.serviceVersionAuditAspect(params);
  24. }
  25. catch (RuntimeException e) {
  26. }
  27. return new HashMap<>();
  28. }
  29. }

MsgHandlerProcessor注册器

但是MsgHandlerContext当中的handlerMap也就是我们具体的一个个的实际hanlder是何时加入到容器的呢?这里就需要定义实现了Bean工厂的MsgHandlerProcessor即注册器,实现postProcessBeanFactory方法。定义包扫描,扫描hanlder所在包当中打上@PassiveMsgHandlerType注解的hanlder。使具体的hanlder处理器PublishServiceVersionMsgHandlerApprovePublishServiceVersionMsgHandler在程序启动的时候就加载到Spring容器当中。
PublishServiceVersionMsgHandlerApprovePublishServiceVersionMsgHandler要打上自定义注解@PassiveMsgHandlerType,并且注解@PassiveMsgHandlerType的value值要与业务内@AiPassiveMsg注解的sceneType值保持匹配,因为注册阶段MsgHandlerProcessor会根据@PassiveMsgHandlerType的value值作为key进行hanlder的注册,加载阶段MsgHandlerContext会根据@AiPassiveMsg的sceneType值作为key进行获取。**@PassiveMsgHandlerType****value**值和**@AiPassiveMsg****sceneType**值保持一致,能确保获取到的hanlder是符合预期的hanlder

  1. package com.iwhalecloud.aiFactory.aspect.msghandler;
  2. import com.google.common.collect.Maps;
  3. import com.iwhalecloud.aiFactory.common.aspect.AiPassiveMsg;
  4. import com.iwhalecloud.aiFactory.common.util.ClassScaner;
  5. import org.springframework.beans.BeansException;
  6. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  7. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  8. import org.springframework.stereotype.Component;
  9. import java.util.Map;
  10. /**
  11. * @description:
  12. * @author: hasee
  13. * @create: 2019-06-14 15:02
  14. **/
  15. @Component
  16. public class MsgHandlerProcessor implements BeanFactoryPostProcessor {
  17. private static final String HANDLER_PACKAGE = "com.iwhalecloud.aiFactory.aspect.msghandler.process";
  18. /**
  19. * 扫描@PassiveMsgHandlerType,MsgHandlerContext,将其注册到spring容器
  20. *
  21. * @param beanFactory bean工厂
  22. */
  23. @Override
  24. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  25. Map<String, Class> handlerMap = Maps.newHashMapWithExpectedSize(3);
  26. //只扫描带有@PassiveMsgHandlerType注解的handler
  27. ClassScaner.scan(HANDLER_PACKAGE, PassiveMsgHandlerType.class).forEach(clazz -> {
  28. // 获取注解中的类型值
  29. String type = clazz.getAnnotation(PassiveMsgHandlerType.class).value();
  30. // 将注解中的类型值作为key,对应的类作为value,保存在Map中
  31. handlerMap.put(type, clazz);
  32. beanFactory.registerSingleton(clazz.getName(),clazz);
  33. });
  34. // 初始化HandlerContext,将其注册到spring容器中
  35. MsgHandlerContext context = new MsgHandlerContext(handlerMap);
  36. beanFactory.registerSingleton(MsgHandlerContext.class.getName(), context);
  37. }
  38. }

ClassScaner包扫描

实现了ResourceLoaderAware接口的setResourceLoader(ResourceLoader var1)方法

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. package org.springframework.context;
  6. import org.springframework.beans.factory.Aware;
  7. import org.springframework.core.io.ResourceLoader;
  8. public interface ResourceLoaderAware extends Aware {
  9. void setResourceLoader(ResourceLoader var1);
  10. }

ClassScaner

  1. package com.iwhalecloud.aiFactory.common.util;
  2. import org.apache.commons.lang3.ArrayUtils;
  3. import org.springframework.beans.factory.BeanDefinitionStoreException;
  4. import org.springframework.context.ResourceLoaderAware;
  5. import org.springframework.core.io.Resource;
  6. import org.springframework.core.io.ResourceLoader;
  7. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
  8. import org.springframework.core.io.support.ResourcePatternResolver;
  9. import org.springframework.core.io.support.ResourcePatternUtils;
  10. import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
  11. import org.springframework.core.type.classreading.MetadataReader;
  12. import org.springframework.core.type.classreading.MetadataReaderFactory;
  13. import org.springframework.core.type.filter.AnnotationTypeFilter;
  14. import org.springframework.core.type.filter.TypeFilter;
  15. import org.springframework.util.StringUtils;
  16. import org.springframework.util.SystemPropertyUtils;
  17. import java.io.IOException;
  18. import java.lang.annotation.Annotation;
  19. import java.util.HashSet;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Set;
  23. /**
  24. * @description:
  25. * @author: hasee
  26. * @create: 2019-06-14 15:06
  27. **/
  28. public class ClassScaner implements ResourceLoaderAware {
  29. private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
  30. private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
  31. private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
  32. private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
  33. @SafeVarargs
  34. public static Set<Class<?>> scan(String[] basePackages, Class<? extends Annotation>... annotations) {
  35. ClassScaner cs = new ClassScaner();
  36. if (ArrayUtils.isNotEmpty(annotations)) {
  37. for (Class anno : annotations) {
  38. cs.addIncludeFilter(new AnnotationTypeFilter(anno));
  39. }
  40. }
  41. Set<Class<?>> classes = new HashSet<>();
  42. for (String s : basePackages) {
  43. classes.addAll(cs.doScan(s));
  44. }
  45. return classes;
  46. }
  47. @SafeVarargs
  48. public static Set<Class<?>> scan(String basePackages, Class<? extends Annotation>... annotations) {
  49. return ClassScaner.scan(StringUtils.tokenizeToStringArray(basePackages, ",; \t\n"), annotations);
  50. }
  51. public final ResourceLoader getResourceLoader() {
  52. return this.resourcePatternResolver;
  53. }
  54. @Override
  55. public void setResourceLoader(ResourceLoader resourceLoader) {
  56. this.resourcePatternResolver = ResourcePatternUtils
  57. .getResourcePatternResolver(resourceLoader);
  58. this.metadataReaderFactory = new CachingMetadataReaderFactory(
  59. resourceLoader);
  60. }
  61. public void addIncludeFilter(TypeFilter includeFilter) {
  62. this.includeFilters.add(includeFilter);
  63. }
  64. public void addExcludeFilter(TypeFilter excludeFilter) {
  65. this.excludeFilters.add(0, excludeFilter);
  66. }
  67. public void resetFilters(boolean useDefaultFilters) {
  68. this.includeFilters.clear();
  69. this.excludeFilters.clear();
  70. }
  71. public Set<Class<?>> doScan(String basePackage) {
  72. Set<Class<?>> classes = new HashSet<>();
  73. try {
  74. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
  75. + org.springframework.util.ClassUtils
  76. .convertClassNameToResourcePath(SystemPropertyUtils
  77. .resolvePlaceholders(basePackage))
  78. + "/**/*.class";
  79. Resource[] resources = this.resourcePatternResolver
  80. .getResources(packageSearchPath);
  81. for (int i = 0; i < resources.length; i++) {
  82. Resource resource = resources[i];
  83. if (resource.isReadable()) {
  84. MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
  85. if ((includeFilters.isEmpty() && excludeFilters.isEmpty()) || matches(metadataReader)) {
  86. try {
  87. classes.add(Class.forName(metadataReader
  88. .getClassMetadata().getClassName()));
  89. }
  90. catch (ClassNotFoundException e) {
  91. LoggerUtil.info(e.getMessage());
  92. }
  93. }
  94. }
  95. }
  96. }
  97. catch (IOException ex) {
  98. throw new BeanDefinitionStoreException(
  99. "I/O failure during classpath scanning", ex);
  100. }
  101. return classes;
  102. }
  103. protected boolean matches(MetadataReader metadataReader) throws IOException {
  104. for (TypeFilter tf : this.excludeFilters) {
  105. if (tf.match(metadataReader, this.metadataReaderFactory)) {
  106. return false;
  107. }
  108. }
  109. for (TypeFilter tf : this.includeFilters) {
  110. if (tf.match(metadataReader, this.metadataReaderFactory)) {
  111. return true;
  112. }
  113. }
  114. return false;
  115. }
  116. }

PassiveMsgHandlerType注解

PassiveMsgHandlerType注解,各个具体的hanlder实现类跟据PassiveMsgHandlerType标识,包扫描工具类就是根据此注解找到我们各个具体的hanlder实现类。

  1. package com.iwhalecloud.aiFactory.aspect.msghandler;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Inherited;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. @Target(ElementType.TYPE)
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Documented
  11. @Inherited
  12. public @interface PassiveMsgHandlerType {
  13. String value();
  14. }

MsgHandlerContext加载器

怎么从容器中读取这些hanlder处理器呢?
这里就需要定义加载器,即上下文类MsgHandlerContext
AiPassiveMsgHandler instance = msgHandlerContext.getInstance(sceneType);sceneType名为key获取到hanlder的clazz对象

  1. package com.iwhalecloud.aiFactory.aspect.msghandler;
  2. import com.iwhalecloud.aiFactory.common.web.SpringContextUtil;
  3. import java.util.Map;
  4. /**
  5. * @description:
  6. * @author: hasee
  7. * @create: 2022-04-25 09:13
  8. **/
  9. public class MsgHandlerContext {
  10. private Map<String, Class> handlerMap;
  11. public MsgHandlerContext(Map<String, Class> handlerMap) {
  12. this.handlerMap = handlerMap;
  13. }
  14. public AiPassiveMsgHandler getInstance(String type) {
  15. Class clazz = handlerMap.get(type);
  16. if (clazz == null) {
  17. throw new IllegalArgumentException("not found handler for type: " + type);
  18. }
  19. return (AiPassiveMsgHandler) SpringContextUtil.getBean(clazz);
  20. }
  21. }

策略模式优势

我们在写代码的时候,常常会遇到不同的情况不同处理,通常情况下我们会使用if…else if ….else…. 但随着程序的不断扩展,可能if…else if 会越来越多,可维护性就会不断降低,而且代码的可读性也会越来越差,所以这里推荐大家使用策略模式。在这里以Java的项目来进行演示。
image.png
以订单的多状态处理来进行设计:

  • 提供 IHander类进行统一的handler的定义
  • 抽象AbstractOrderStatusHandler进行handler的默认的一些方法的定义
  • OrderCommitStatusHandler(具体的实现handler)
  • OrderPayStatusHandler
  • Order…StatusHandler
  • 通过Strategy进行控制,利用Map的特性根据handler的键获取对应的真正的处理handler实现的常用的策略模式

[

](https://blog.csdn.net/qq_34798605/article/details/123321434)