实现扫描规定的包下的类中的注解参数和对应的类名,并把包下的类名和注解参数进行业务处理。

实现扫描规定的包下的类中的注解参数和对应的类名,并把包下的类名和注解参数进行业务处理。
1、获取所有包下的类名的工具类

package com.sxgw.pcops.im.base.scan;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.sxgw.pcops.common.entity.MqEntityType;
import com.sxgw.pcops.im.base.handler.MqBaseHandler;
import com.sxgw.pcops.im.base.tool.MqHandlerUtil;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 获取所有包下的类名的工具类
 *
 * @author 
 * @since 2020/11/2
 **/
@Component
public class ClassUtils {

  private static final String FILE_STR = "file";
  private static final String JAR_STR = "jar";

  /**
   * 获取某包下所有类
   *
   * @param packageName 包名
   * @param isRecursion 是否遍历子包
   * @return 类的完整名称
   */
  public static Set<String> getClassName(String packageName, boolean isRecursion) throws ClassNotFoundException {
    Set<String> classNames = null;
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    String packagePath = packageName.replace(".", "/");
    URL url = loader.getResource(packagePath);
    if (url != null) {
      String protocol = url.getProtocol();
      if (FILE_STR.equals(protocol)) {
        classNames = getClassNameFromDir(url.getPath(), packageName, isRecursion);
      } else if (JAR_STR.equals(protocol)) {
        JarFile jarFile = null;
        try {
          jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
        } catch (Exception e) {
          e.printStackTrace();
        }
        if (jarFile != null) {
          classNames = getClassNameFromJar(jarFile.entries(), packageName, isRecursion);
        }
      }
    } else {
      /*从所有的jar包中查找包名*/
      classNames = getClassNameFromJars(((URLClassLoader) loader).getURLs(), packageName, isRecursion);
    }
    return classNames;
  }

  /**
   * 从项目文件获取某包下所有类
   *
   * @param filePath    文件路径
   * @param isRecursion 是否遍历子包
   * @return 类的完整名称
   */
  private static Set<String> getClassNameFromDir(String filePath, String packageName, boolean isRecursion) throws ClassNotFoundException {
    Set<String> className = new HashSet<>();
    File file = new File(filePath);
    File[] files = file.listFiles();
    if (files == null) {
      return className;
    }
    for (File childFile : files) {
      if (childFile.isDirectory()) {
        if (isRecursion) {
          className.addAll(getClassNameFromDir(childFile.getPath(), packageName + "." + childFile.getName(), isRecursion));
        }
      } else {
        String fileName = childFile.getName();
        if (fileName.endsWith(".class") && !fileName.contains("$")) {
          String classPath = packageName + "." + fileName.replace(".class", "");
          addCollectionIsHandler(className, classPath);
        }
      }
    }
    return className;
  }

  private static void addCollectionIsHandler(Set<String> set, String className) throws ClassNotFoundException {
    Class<?> aClass = Class.forName(className);
    if (MqBaseHandler.class.isAssignableFrom(aClass)) {
      HandlerName handlerName = aClass.getAnnotation(HandlerName.class);
      String handlerStr = aClass.getSimpleName();
      if (null != handlerName && !StringUtils.isEmpty(handlerName.value())) {
        handlerStr = handlerName.value();
      }
      // ----*-**-该部分为扫描到的类名和类对应的注解,注解为HandlerName 的参数*** 
      MqHandlerUtil.put(handlerStr, aClass);
      set.add(className);
    }
  }

  private static Set<String> getClassNameFromJar(Enumeration<JarEntry> jarEntries, String packageName, boolean isRecursion)
      throws ClassNotFoundException {
    Set<String> classNames = new HashSet<>();

    while (jarEntries.hasMoreElements()) {
      JarEntry jarEntry = jarEntries.nextElement();
      if (!jarEntry.isDirectory()) {
        String entryName = jarEntry.getName().replace("/", ".");
        if (entryName.endsWith(".class") && !entryName.contains("$") && entryName.startsWith(packageName)) {
          entryName = entryName.replace(".class", "");
          if (isRecursion) {
            addCollectionIsHandler(classNames, entryName);
//            classNames.add(entryName);
          } else if (!entryName.replace(packageName + ".", "").contains(".")) {
            addCollectionIsHandler(classNames, entryName);
//            classNames.add(entryName);
          }
        }
      }
    }
    return classNames;
  }

  /**
   * 从所有jar中搜索该包,并获取该包下所有类
   *
   * @param urls        URL集合
   * @param packageName 包路径
   * @param isRecursion 是否遍历子包
   * @return 类的完整名称
   */
  private static Set<String> getClassNameFromJars(URL[] urls, String packageName, boolean isRecursion) throws ClassNotFoundException {
    Set<String> classNames = new HashSet<>();
    for (URL url : urls) {
      String classPath = url.getPath();
      //不必搜索classes文件夹
      if (classPath.endsWith("classes/")) {
        continue;
      }
      JarFile jarFile = null;
      try {
        jarFile = new JarFile(classPath.substring(classPath.indexOf("/")));
      } catch (IOException e) {
        e.printStackTrace();
      }
      if (jarFile != null) {
        classNames.addAll(getClassNameFromJar(jarFile.entries(), packageName, isRecursion));
      }
    }
    return classNames;
  }
}

2、该部分为扫描包的注解

package com.sxgw.pcops.im.base.scan;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * 启用mq处理自动扫描
 *
 * @author 
 * @since 2020/11/1 10:42
 **/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableMqHandlerScanConfig.class)
public @interface EnableMqHandlerScan {

  //传入包名
  String[] packages() default "";
}

3、该部分为扫描包的配置文件

package com.sxgw.pcops.im.base.scan;

import com.alibaba.fastjson.JSON;
import com.sxgw.pcops.common.entity.MqEntityType;
import com.sxgw.pcops.im.base.tool.MqHandlerUtil;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 自己的定义的自动注解配置类
 *
 * @author 
 * @since 2020/11/2 10:45
 **/
public class EnableMqHandlerScanConfig implements ImportSelector {

  private static Logger logger = LoggerFactory.getLogger(EnableMqHandlerScanConfig.class);

  @SneakyThrows
  @Override
  public String[] selectImports(AnnotationMetadata annotationMetadata) {
    //获取EnableEcho注解的所有属性的value
    Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(EnableMqHandlerScan.class.getName());
    if (attributes == null) {
      return new String[0];
    }
    //获取package属性的value
    String[] packages = (String[]) attributes.get("packages");
    if (packages == null || packages.length <= 0 || StringUtils.isEmpty(packages[0])) {
      return new String[0];
    }
    logger.info("加载该包所有类到spring容器中的包名为:" + Arrays.toString(packages));
    Set<String> classNames = new HashSet<>();

    for (String packageName : packages) {
      Set<String> className = ClassUtils.getClassName(packageName, true);
      logger.info("扫描包:{},找到得类:{}", new Object[]{packageName, className == null ? "null" : JSON.toJSONString(className)});
      if (null != className) {
        classNames.addAll(className);
      }
    }
    String[] returnClassNames = new String[classNames.size()];
    returnClassNames = classNames.toArray(returnClassNames);
    return returnClassNames;
  }
}

4、该部分为自定义的HandlerName注解

package com.sxgw.pcops.im.base.scan;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Indexed;

/**
 * 处理器名称
 *
 * @author
 * @since 2020/11/1 10:42
 **/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface HandlerName {

  //名称
  String value() default "";
}

5、该部分为被扫描的类,在该类添加注解即可被扫描到

package com.sxgw.pcops.flow.server.task;

import com.sxgw.pcops.common.entity.MqEntity;
import com.sxgw.pcops.flow.server.service.FlowMainService;
import com.sxgw.pcops.im.base.handler.MqBaseHandler;
import com.sxgw.pcops.im.base.scan.HandlerName;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author sumingyu 2020-11-03 实现客户端申请故障后异步监听mq并派发到客服
 */
@Slf4j
@HandlerName("waitTurnFlow")  // **该注解为被扫描的参数**
public class FlowHandler extends MqBaseHandler {  //2

  @Autowired
  private FlowMainService flowMainService;

  //4
  @Override
  protected void handlerMsg(MqEntity mqEntity) {
    //@TODO 做业务处理

    /*****随机分配工单*******/
    String flowNo = mqEntity.getData();

    boolean success = flowMainService.randomAllotFlow(flowNo);
    if (success) {
      log.info("异步随机分配工单成功!");
    } else {
      log.info("异步随机分配工单失败!");
    }
    log.info("异步随机分配工单!");

    System.out.println("接收到消息=" + mqEntity.getData());
  }
}

6、该部分为启动类中的配置

package com.sxgw.pcops;

import com.sxgw.pcops.im.base.scan.EnableMqHandlerScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableScheduling
@EnableSwagger2
@EnableCaching
@EnableAsync
@ServletComponentScan
@EnableMqHandlerScan(packages = {"com.sxgw.pcops.im.server.mq.handler", "com.sxgw.pcops.flow.server.task"})
public class ServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class, args);
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值