JAVA获取实现了某接口的类[转载] - 全栈笔记

JAVA获取实现了某接口的类[转载]

任亦伟 默认分类 2015-03-03 229 次浏览 没有评论

这篇文章是转载的,无视原文的评论,总之我需要实现这样的功能!

最近为项目写了一个公式执行功能,其中函数太多,只能写了一个接口,用到哪个函数实现哪个函数.问题来了:怎么知道实现函数接口的类的存在?

想了两个办法:

1:写配置文件,实现一个类,在配置文件里添加一条实现类的路径.但是此方法限制了灵活性.

2:在函数执行前,自动搜索项目path下所有实现了接口的类.

方法1很简单,不论是xml还是properties都可以.这里就不用多说了.

方法2在网上找了很多资料,都说使用ClassLoader下的getResource(s)方式,但是经过我测试,项目没打包时可以正常工作,一旦打成jar包(我用eclipse3.4的导出成可执行jar),就不行了.

最后参考这些原理,想了下,自己实现了一个.

首先得到项目的path,使用System.getProperty(“java.class.path”),然后逐个查找path里出现的文件,如果是文件夹,遍历文件夹,加载类,如果是jar或者zip,遍历此压缩文件查找类.然后判断类是否实现了接口即可.

查找的工具类叫做FunctionHelper

01
/**
02
 * 函数的接口.<br>
03
 * 所有函数都应该实现此接口或者继承此接口的抽象实现:{@link AbstractFunction}<br>
04
 * 所有实现此接口的函数,需要注册才能被加载和使用.<br>
05
 * 注册的方式:
06
 * <ul>
07
 * <li>在functions.xml中进行注册(仅限本包中)</li>
08
 * <li>放置在本接口所在的包的子包impl包下,此时,类名就被认为是函数名.若本接口位于test.formula,
09
 * 则放置实现于test.formula.impl下可被自动进行注册</li>
10
 * </ul>
11
 * 
12
 */
13
public interface IFunction {}

判断类是否实现了接口

01
    /**
02
     * 判断类是否函数类.<br>
03
     * 首先,类不能是抽象的,其次,类必须实现函数接口
04
     * 
05
     * @param c
06
     *            类
07
     * @return 是否是函数类
08
     */
09
    public static boolean isFunction(Class<?> c) {
10
        if (c == null) {
11
            return false;
12
        }
13
        if (c.isInterface()) {
14
            return false;
15
        }
16
        if (Modifier.isAbstract(c.getModifiers())) {
17
            return false;// 抽象
18
        }
19
        // Class<?>[] interfaces = c.getInterfaces();
20
        // if (interfaces == null || interfaces.length == 0) {
21
        // return false;
22
        // }
23
        // for (Class<?> i : interfaces) {
24
        // if (i == IFunction.class) {
25
        // return true;
26
        // }
27
        // }
28
        return IFunction.class.isAssignableFrom(c);
29
    }

查找path下所有的文件

01
    /**
02
     * 获取项目的path下所有的文件夹和文件
03
     * 
04
     * @return 文件列表
05
     */
06
    private static List<File> listPaths() {
07
        List<File> files = new ArrayList<File>();
08
        String jars = System.getProperty("java.class.path");
09
        if (jars == null) {
10
            System.err.println("java.class.path is null!");
11
            return files;
12
        }
13
        URL root = FunctionHelper.class.getClassLoader().getResource("");
14
        if (root == null) {
15
            System.err.println("path root is null!");
16
            return files;
17
        }
18
        String path = null;
19
        try {
20
            path = URLDecoder.decode(root.getFile(), "UTF-8");
21
        } catch (UnsupportedEncodingException e) {
22
            e.printStackTrace();
23
            return files;
24
        }
25
        File dir = new File(path);
26
        String[] array = (jars).split(";");
27
        if (array != null) {
28
            for (String s : array) {
29
                if (s == null) {
30
                    continue;
31
                }
32
                File f = new File(s);
33
                if (f.exists()) {
34
                    files.add(f);
35
                } else {//有些jar就在系统目录下,省略了路径,要加上
36
                    File jar = new File(dir, s);
37
                    if (jar.exists()) {
38
                        files.add(jar);
39
                    }
40
                }
41
            }
42
        }
43
        return files;
44
    }

开始遍历上面的文件:

01
    /**
02
     * 获取包下所有的函数实现类
03
     * 
04
     * @param pkg
05
     *            包名,此处只是为了限定,防止漫无目的的查找.不用设置也可以,就要每找到一个类就要加载一次判断了
06
     * @return 类列表
07
     */
08
    private static List<Class<?>> getClasses(String pkg) {
09
        List<Class<?>> list = new ArrayList<Class<?>>();
10
        for (File f : FunctionHelper.listPaths()) {
11
            // 如果是以文件的形式保存在服务器上
12
            if (f.isDirectory()) {
13
                // 获取包的物理路径
14
                String path = pkg.replace('.', File.separatorChar);
15
                FunctionHelper.dirWalker(path, f, list);
16
            } else {//尝试是否是jar文件
17
                // 获取jar
18
                JarFile jar = null;
19
                try {
20
                    jar = new JarFile(f);
21
                } catch (IOException e) {
22
                    // 有可能不是一个jar
23
                }
24
                if (jar == null) {
25
                    continue;
26
                }
27
                String path = pkg.replace('.', '/');
28
                // 从此jar包 得到一个枚举类
29
                Enumeration<JarEntry> entries = jar.entries();
30
                // 同样的进行循环迭代
31
                while (entries.hasMoreElements()) {
32
                    // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
33
                    JarEntry entry = entries.nextElement();
34
                    String name = entry.getName();
35
                    // 如果是以/开头的
36
                    if (name.charAt(0) == '/') {
37
                        // 获取后面的字符串
38
                        name = name.substring(1);
39
                    }
40
                    // 如果前半部分和定义的包名相同
41
                    if (name.contains(path)) {
42
                        if (name.endsWith(".class") && !entry.isDirectory()) {
43
                            name = name.replace("/", ".").substring(0,
44
                                    name.lastIndexOf("."));
45
                            try {
46
                                Class<?> c = Class.forName(name);
47
                                if (FunctionHelper.isFunction(c)) {
48
                                    list.add(c);
49
                                }
50
                            } catch (Exception e) {
51
                                // 找不到无所谓了
52
                            }
53
                        }
54
                    }
55
                }
56
            }
57
        }
58
        return list;
59
    }

dirWalker,文件夹遍历

01
    /**
02
     * 遍历文件夹下所有的类
03
     * 
04
     * @param path
05
     *            包路径
06
     * @param file
07
     *            文件
08
     * @param list
09
     *            保存类列表
10
     */
11
    private static void dirWalker(String path, File file, List<Class<?>> list) {
12
        if (file.exists()) {
13
            if (file.isDirectory()) {
14
                for (File f : file.listFiles()) {
15
                    FunctionHelper.dirWalker(path, f, list);
16
                }
17
            } else {
18
                Class<?> c = FunctionHelper.loadClassByFile(path, file);
19
                if (c != null) {
20
                    list.add(c);
21
                }
22
            }
23
        }
24
    }
25

从文件加载类

01
    /**
02
     * 从文件加载类
03
     * 
04
     * @param pkg
05
     *            包路径
06
     * @param file
07
     *            文件
08
     * @return 类或者null
09
     */
10
    private static Class<?> loadClassByFile(String pkg, File file) {
11
        if (!file.isFile()) {
12
            return null;
13
        }
14
        String name = file.getName();
15
        if (name.endsWith(".class")) {
16
            String ap = file.getAbsolutePath();
17
            if (!ap.contains(pkg)) {
18
                return null;
19
            }
20
            name = ap.substring(ap.indexOf(pkg) + pkg.length());
21
            if (name.startsWith(File.separator)) {
22
                name = name.substring(1);
23
            }
24
            String path = (pkg + "." + name.substring(0, name.lastIndexOf(".")))
25
                    .replace(File.separatorChar, '.');
26
            try {
27
                Class<?> c = Class.forName(path);
28
                if (FunctionHelper.isFunction(c)) {
29
                    return c;
30
                }
31
            } catch (ClassNotFoundException e) {
32
                // do nothing
33
            }
34
        }
35
        return null;
36
    }

原文来自:http://www.iteye.com/topic/811684

发表评论

回顶部