美文网首页
Spring的Bean扫描器

Spring的Bean扫描器

作者: 知止9528 | 来源:发表于2019-01-17 20:44 被阅读0次

    一:接口定义

    public interface ClassScanner {
    
    
        /**
         * 获取指定包名中的所有类
         */
        List<Class<?>> getClassList(String packageName);
    
    
        /**
         * 获取指定包名中指定注解的相关类
         */
        List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass);
    
    
        /**
         * 获取指定包名中指定父类或接口的相关类
         */
        List<Class<?>> getClassListBySuper(String packageName, Class<?> superClass)
    

    二.抽象模板

    public abstract class ClassTemplate {
    
        private static final Logger logger = LoggerFactory.getLogger(ClassTemplate.class);
    
        protected final String packageName;
    
        protected ClassTemplate(String packageName) {
            this.packageName = packageName;
        }
    
        public final List<Class<?>> getClassList() {
            List<Class<?>> classList = new ArrayList<Class<?>>();
            try {
                // 从包名获取 URL 类型的资源
                Enumeration<URL> urls = ClassUtil.getClassLoader().getResources(packageName.replace(".", "/"));
                // 遍历 URL 资源
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    if (url != null) {
                        // 获取协议名(分为 file 与 jar)
                        String protocol = url.getProtocol();
                        if (protocol.equals("file")) {
                            // 若在 class 目录中,则执行添加类操作
                            String packagePath = url.getPath();
                            addClass(classList, packagePath, packageName);
                        } else if (protocol.equals("jar")) {
                            // 若在 jar 包中,则解析 jar 包中的 entry
                            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                            JarFile jarFile = jarURLConnection.getJarFile();
                            Enumeration<JarEntry> jarEntries = jarFile.entries();
                            while (jarEntries.hasMoreElements()) {
                                JarEntry jarEntry = jarEntries.nextElement();
                                String jarEntryName = jarEntry.getName();
                                // 判断该 entry 是否为 class
                                if (jarEntryName.endsWith(".class")) {
                                    // 获取类名
                                    String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                    // 执行添加类操作
                                    doAddClass(classList, className);
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("获取类出错!", e);
            }
            return classList;
        }
    
        private void addClass(List<Class<?>> classList, String packagePath, String packageName) {
            try {
                // 获取包名路径下的 class 文件或目录
                File[] files = new File(packagePath).listFiles(new FileFilter() {
                    @Override
                    public boolean accept(File file) {
                        return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
                    }
                });
                // 遍历文件或目录
                for (File file : files) {
                    String fileName = file.getName();
                    // 判断是否为文件或目录
                    if (file.isFile()) {
                        // 获取类名
                        String className = fileName.substring(0, fileName.lastIndexOf("."));
                        if (StringUtil.isNotEmpty(packageName)) {
                            className = packageName + "." + className;
                        }
                        // 执行添加类操作
                        doAddClass(classList, className);
                    } else {
                        // 获取子包
                        String subPackagePath = fileName;
                        if (StringUtil.isNotEmpty(packagePath)) {
                            subPackagePath = packagePath + "/" + subPackagePath;
                        }
                        // 子包名
                        String subPackageName = fileName;
                        if (StringUtil.isNotEmpty(packageName)) {
                            subPackageName = packageName + "." + subPackageName;
                        }
                        // 递归调用
                        addClass(classList, subPackagePath, subPackageName);
                    }
                }
            } catch (Exception e) {
                logger.error("添加类出错!", e);
            }
        }
    
        private void doAddClass(List<Class<?>> classList, String className) {
            // 加载类
            Class<?> cls = ClassUtil.loadClass(className, false);
            // 判断是否可以添加类
            if (checkAddClass(cls)) {
                // 添加类
                classList.add(cls);
            }
        }
    
        /**
         * 验证是否允许添加类
         */
        public abstract boolean checkAddClass(Class<?> cls);
    }
    

    三.默认实现

    public class DefaultClassScanner implements ClassScanner {
    
        @Override
        public List<Class<?>> getClassList(String packageName) {
            return new ClassTemplate(packageName) {
                @Override
                public boolean checkAddClass(Class<?> cls) {
                    String className = cls.getName();
                    String pkgName = className.substring(0, className.lastIndexOf("."));
                    return pkgName.startsWith(packageName);
                }
            }.getClassList();
        }
    
        @Override
        public List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass) {
            return new AnnotationClassTemplate(packageName, annotationClass) {
                @Override
                public boolean checkAddClass(Class<?> cls) {
                    return cls.isAnnotationPresent(annotationClass);
                }
            }.getClassList();
        }
    
        @Override
        public List<Class<?>> getClassListBySuper(String packageName, Class<?> superClass) {
            return new SupperClassTemplate(packageName, superClass) {
                @Override
                public boolean checkAddClass(Class<?> cls) {
                    return superClass.isAssignableFrom(cls) && !superClass.equals(cls);
                }
            }.getClassList();
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring的Bean扫描器

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