美文网首页
扫描指定注解并加入到 Spring 上下文中 ClassScan

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

作者: 赛亚人之神 | 来源:发表于2020-02-28 16:48 被阅读0次

    ClassScanner

    @Slf4j
    public class ClassScanner implements ResourceLoaderAware {
    
      private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
      private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
    
      private final List<TypeFilter> includeFilters = new LinkedList<>();
      private final List<TypeFilter> 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<Class> scan(String basePackage, Class<? extends Annotation>... annotations) {
        ClassScanner classScanner = new ClassScanner();
    
        for (Class<? extends Annotation> annotation : annotations) {
          classScanner.addIncludeFilter(new AnnotationTypeFilter(annotation));
        }
        return classScanner.doScan(basePackage);
      }
    
      /**
       * 扫描多个路径下包含指定注解的类
       * @param basePackages
       * @param annotations
       * @return
       */
      public static Set<Class> scan(String[] basePackages, Class<? extends Annotation>... annotations) {
        ClassScanner classScanner = new ClassScanner();
        for (Class<? extends Annotation> annotation : annotations) {
          classScanner.addIncludeFilter(new AnnotationTypeFilter(annotation));
        }
    
        Set<Class> classes = new HashSet<>();
        for (String basePackage : basePackages) {
          classes.addAll(classScanner.doScan(basePackage));
        }
    
        return classes;
      }
    
      /**
       * 扫描指定路径下的类信息
       * @param basePackage
       * @return
       */
      public Set<Class> doScan(String basePackage) {
        Set<Class> 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> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
      }
    
      public static <T> T getBean(Class<T> 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<String, Class> 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<String, Class> handlerMap;
    
      public HandlerContext(Map<String, Class> 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 上下文中 ClassScan

          本文链接:https://www.haomeiwen.com/subject/ndblhhtx.html