扫描指定注解并加入到 Spring 上下文中 ClassScanner

ClassScanner

@Slf4j
public class ClassScanner implements ResourceLoaderAware {

  private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
  private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);

  private final List includeFilters = new LinkedList<>();
  private final List excludeFilters = new LinkedList<>();


  @Override
  public void setResourceLoader(ResourceLoader resourceLoader) {
    this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
  }

  public void addIncludeFilter(TypeFilter includeFilter) {
    this.includeFilters.add(includeFilter);
  }

  public void addExcludeFilter(TypeFilter excludeFilter) {
    this.excludeFilters.add(0, excludeFilter);
  }

  public void resetFilters(boolean useDefaultFilters) {
    this.includeFilters.clear();
    this.excludeFilters.clear();
  }

  /**
   * 扫描指定路径指定注解的类
   * @param basePackage
   * @param annotations
   * @return
   */
  public static Set scan(String basePackage, Class... annotations) {
    ClassScanner classScanner = new ClassScanner();

    for (Class annotation : annotations) {
      classScanner.addIncludeFilter(new AnnotationTypeFilter(annotation));
    }
    return classScanner.doScan(basePackage);
  }

  /**
   * 扫描多个路径下包含指定注解的类
   * @param basePackages
   * @param annotations
   * @return
   */
  public static Set scan(String[] basePackages, Class... annotations) {
    ClassScanner classScanner = new ClassScanner();
    for (Class annotation : annotations) {
      classScanner.addIncludeFilter(new AnnotationTypeFilter(annotation));
    }

    Set classes = new HashSet<>();
    for (String basePackage : basePackages) {
      classes.addAll(classScanner.doScan(basePackage));
    }

    return classes;
  }

  /**
   * 扫描指定路径下的类信息
   * @param basePackage
   * @return
   */
  public Set doScan(String basePackage) {
    Set classes = new HashSet<>();

    // 扫描路径
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
        + ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage))
        + "/**/*.class";
    try {

      // 获取指定扫描路径的资源
      Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

      for (Resource resource : resources) {
        if (resource.isReadable()) {

          MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);

          if ((this.includeFilters.size() == 0 && this.excludeFilters.size() == 0) || matches(metadataReader)) {

            try {
              // 返回符合条件的资源
              classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
            } catch (ClassNotFoundException e) {
              log.error("class forName 异常:", e);
            }

          }
        }
      }
    } catch (IOException e) {

      log.error("扫描加载资源io异常:", e);
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", e);
    }

    return classes;
  }


  /**
   * 资源是否匹配
   * @param metadataReader
   * @return
   * @throws IOException
   */
  private boolean matches(MetadataReader metadataReader) throws IOException {

    for (TypeFilter excludeFilter : this.excludeFilters) {
      if (excludeFilter.match(metadataReader, this.metadataReaderFactory)) {
        return false;
      }
    }

    for (TypeFilter includeFilter : this.includeFilters) {
      if (includeFilter.match(metadataReader, this.metadataReaderFactory)) {
        return true;
      }
    }

    return false;
  }
}
  1. SpringContextUtil
@Getter
@Component
public class SpringContextUtil implements ApplicationContextAware {
  private static ApplicationContext applicationContext = null;

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    SpringContextUtil.applicationContext = applicationContext;
  }

  public static  T getBean(String beanName) {
    return (T) applicationContext.getBean(beanName);
  }

  public static  T getBean(Class requireType) {
    return applicationContext.getBean(requireType);
  }
}

  1. HandlerProcessor 扫描指定路径下的实现 Bean,加载到上下文中
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {

  public static final String HANDLER_PACKAGE = "com.trade.service.strategy.impl";

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    Map handlerMap = Maps.newHashMapWithExpectedSize(4);

    ClassScanner.scan(HANDLER_PACKAGE, OrderType.class).forEach(clazz -> {

      // 获取注解中的类型值
      OrderType orderType = (OrderType) clazz.getAnnotation(OrderType.class);
      String type = orderType.value();

      // 将注解中的类型值作为 key,对应类作为 value 保存在 Map 中
      handlerMap.put(type, clazz);
    });

    // 初始化 HandlerContext,将其注册到 spring 容器中
    HandlerContext context = new HandlerContext(handlerMap);

    beanFactory.registerSingleton(HandlerContext.class.getName(), context);
  }
}

  1. HandlerContext
public class HandlerContext {

  private Map handlerMap;

  public HandlerContext(Map handlerMap) {
    this.handlerMap = handlerMap;
  }

  /**
   * 获取对应交易类型的处理类
   * @param type
   * @return
   */
  public AbstractHandler getInstance(String type) {
    Class clazz = handlerMap.get(type);

    if (clazz == null) {
      throw new IllegalArgumentException("未找到订单类型【" + type + "】的处理类");
    }

    return (AbstractHandler) SpringContextUtil.getBean(clazz);
  }
}

  1. OrderType
@Documented
@Inherited
@Retention(value = RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface OrderType {

  String value() default "";
}

你可能感兴趣的:(扫描指定注解并加入到 Spring 上下文中 ClassScanner)