- 浏览: 182984 次
- 性别:
- 来自: 北京
最新评论
-
u011374223:
获取颜色的方法有两个,07xssfWORKBOOK的需要用这个 ...
apache poi读取excel中的颜色,真是坑爹啊 -
zhangtcb:
读取的颜色和Excel中的不一样啊
apache poi读取excel中的颜色,真是坑爹啊 -
LD_21:
...
log4j日志文件的相对路径 -
xfxlch:
upThx
来,让我们一起画个印章吧 -
xinxinlong:
单元格的style里面有个颜色,如果双击单元格,里面的文字选中 ...
apache poi读取excel中的颜色,真是坑爹啊
最近为项目写了一个公式执行功能,其中函数太多,只能写了一个接口,用到哪个函数实现哪个函数.问题来了:怎么知道实现函数接口的类的存在?
想了两个办法:
1:写配置文件,实现一个类,在配置文件里添加一条实现类的路径.但是此方法限制了灵活性.
2:在函数执行前,自动搜索项目path下所有实现了接口的类.
方法1很简单,不论是xml还是properties都可以.这里就不用多说了.
方法2在网上找了很多资料,都说使用ClassLoader下的getResource(s)方式,但是经过我测试,项目没打包时可以正常工作,一旦打成jar包(我用eclipse3.4的导出成可执行jar),就不行了.
最后参考这些原理,想了下,自己实现了一个.
首先得到项目的path,使用System.getProperty("java.class.path"),然后逐个查找path里出现的文件,如果是文件夹,遍历文件夹,加载类,如果是jar或者zip,遍历此压缩文件查找类.然后判断类是否实现了接口即可.
查找的工具类叫做FunctionHelper
/** * 函数的接口.<br> * 所有函数都应该实现此接口或者继承此接口的抽象实现:{@link AbstractFunction}<br> * 所有实现此接口的函数,需要注册才能被加载和使用.<br> * 注册的方式: * <ul> * <li>在functions.xml中进行注册(仅限本包中)</li> * <li>放置在本接口所在的包的子包impl包下,此时,类名就被认为是函数名.若本接口位于test.formula, * 则放置实现于test.formula.impl下可被自动进行注册</li> * </ul> * */ public interface IFunction {}
判断类是否实现了接口
/** * 判断类是否函数类.<br> * 首先,类不能是抽象的,其次,类必须实现函数接口 * * @param c * 类 * @return 是否是函数类 */ public static boolean isFunction(Class<?> c) { if (c == null) { return false; } if (c.isInterface()) { return false; } if (Modifier.isAbstract(c.getModifiers())) { return false;// 抽象 } // Class<?>[] interfaces = c.getInterfaces(); // if (interfaces == null || interfaces.length == 0) { // return false; // } // for (Class<?> i : interfaces) { // if (i == IFunction.class) { // return true; // } // } return IFunction.class.isAssignableFrom(c); }
查找path下所有的文件
/** * 获取项目的path下所有的文件夹和文件 * * @return 文件列表 */ private static List<File> listPaths() { List<File> files = new ArrayList<File>(); String jars = System.getProperty("java.class.path"); if (jars == null) { System.err.println("java.class.path is null!"); return files; } URL root = FunctionHelper.class.getClassLoader().getResource(""); if (root == null) { System.err.println("path root is null!"); return files; } String path = null; try { path = URLDecoder.decode(root.getFile(), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return files; } File dir = new File(path); String[] array = (jars).split(";"); if (array != null) { for (String s : array) { if (s == null) { continue; } File f = new File(s); if (f.exists()) { files.add(f); } else {//有些jar就在系统目录下,省略了路径,要加上 File jar = new File(dir, s); if (jar.exists()) { files.add(jar); } } } } return files; }
开始遍历上面的文件:
/** * 获取包下所有的函数实现类 * * @param pkg * 包名,此处只是为了限定,防止漫无目的的查找.不用设置也可以,就要每找到一个类就要加载一次判断了 * @return 类列表 */ private static List<Class<?>> getClasses(String pkg) { List<Class<?>> list = new ArrayList<Class<?>>(); for (File f : FunctionHelper.listPaths()) { // 如果是以文件的形式保存在服务器上 if (f.isDirectory()) { // 获取包的物理路径 String path = pkg.replace('.', File.separatorChar); FunctionHelper.dirWalker(path, f, list); } else {//尝试是否是jar文件 // 获取jar JarFile jar = null; try { jar = new JarFile(f); } catch (IOException e) { // 有可能不是一个jar } if (jar == null) { continue; } String path = pkg.replace('.', '/'); // 从此jar包 得到一个枚举类 Enumeration<JarEntry> entries = jar.entries(); // 同样的进行循环迭代 while (entries.hasMoreElements()) { // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果是以/开头的 if (name.charAt(0) == '/') { // 获取后面的字符串 name = name.substring(1); } // 如果前半部分和定义的包名相同 if (name.contains(path)) { if (name.endsWith(".class") && !entry.isDirectory()) { name = name.replace("/", ".").substring(0, name.lastIndexOf(".")); try { Class<?> c = Class.forName(name); if (FunctionHelper.isFunction(c)) { list.add(c); } } catch (Exception e) { // 找不到无所谓了 } } } } } } return list; }
dirWalker,文件夹遍历
/** * 遍历文件夹下所有的类 * * @param path * 包路径 * @param file * 文件 * @param list * 保存类列表 */ private static void dirWalker(String path, File file, List<Class<?>> list) { if (file.exists()) { if (file.isDirectory()) { for (File f : file.listFiles()) { FunctionHelper.dirWalker(path, f, list); } } else { Class<?> c = FunctionHelper.loadClassByFile(path, file); if (c != null) { list.add(c); } } } }
从文件加载类
/** * 从文件加载类 * * @param pkg * 包路径 * @param file * 文件 * @return 类或者null */ private static Class<?> loadClassByFile(String pkg, File file) { if (!file.isFile()) { return null; } String name = file.getName(); if (name.endsWith(".class")) { String ap = file.getAbsolutePath(); if (!ap.contains(pkg)) { return null; } name = ap.substring(ap.indexOf(pkg) + pkg.length()); if (name.startsWith(File.separator)) { name = name.substring(1); } String path = (pkg + "." + name.substring(0, name.lastIndexOf("."))) .replace(File.separatorChar, '.'); try { Class<?> c = Class.forName(path); if (FunctionHelper.isFunction(c)) { return c; } } catch (ClassNotFoundException e) { // do nothing } } return null; }
评论
19 楼
i2534
2010-11-29
taolei0628 写道
何谓灵活性?通过配置来定制系统不算灵活吗?自动搜索实现类可以做到个性化定制吗?
几个简单的问题:
如果你想替换其中某个函数的实现,怎么做?
如果函数是跟外部资源相关的,那么不同的运行环境需要选择不同的实现,怎么做?
我的建议是:配置必需有,自动搜索、加载的方法可以做,但只限于辅助配置管理的工具。
几个简单的问题:
如果你想替换其中某个函数的实现,怎么做?
如果函数是跟外部资源相关的,那么不同的运行环境需要选择不同的实现,怎么做?
我的建议是:配置必需有,自动搜索、加载的方法可以做,但只限于辅助配置管理的工具。
配置文件自然有的,我自己实现的函数就在配置文件里写的.这些是为不能写入配置文件的人做的.譬如,我的jar经过了签名,别人就不能动我的jar了,也就不能再改我的配置文件里,所以要自动加载.至于替换函数,别人可以写个同名函数.因为是先加载我的,后加载他的,而我定的规则就是后加载的覆盖前加载的,这样就实现了替换.
18 楼
taolei0628
2010-11-27
何谓灵活性?通过配置来定制系统不算灵活吗?自动搜索实现类可以做到个性化定制吗?
几个简单的问题:
如果你想替换其中某个函数的实现,怎么做?
如果函数是跟外部资源相关的,那么不同的运行环境需要选择不同的实现,怎么做?
我的建议是:配置必需有,自动搜索、加载的方法可以做,但只限于辅助配置管理的工具。
几个简单的问题:
如果你想替换其中某个函数的实现,怎么做?
如果函数是跟外部资源相关的,那么不同的运行环境需要选择不同的实现,怎么做?
我的建议是:配置必需有,自动搜索、加载的方法可以做,但只限于辅助配置管理的工具。
17 楼
walnut_tom
2010-11-26
你可以参考一下 java.lang.instrument 包的内容。
16 楼
snailke
2010-11-21
一般做项目的话 借口放在一个叫interface包中,实现类放在一个叫impl的包中,这样保证方便
15 楼
liuwei_blog
2010-11-19
设计问题,应该给使用者提供一个方法注入实现类对象,缺省使用你自己的实现类或什么都不做的实现类。
14 楼
i2534
2010-11-17
undancer 写道
将配置文件写在/META-INF/services下,并使用java.util.ServiceLoader去加载。即使以后所有的实现不在同一个jar里也OK,比如java.sql.Driver等接口都是如此实现的。
感谢,又学到一点API.
这位童鞋的话真是精辟啊,我找了google的第一页,做法都一样,很多还是互相转的.都没人试试真的能不能行.....
没办法,只能自己想想解决了.
13 楼
i2534
2010-11-17
引用
哈哈,/META-INF/services来说也是一个配置, Lz要的是最灵活的方法
以前也有过类似的想法,自动扫描一个指定接口的实现或者指定后缀的名字,扫到class后自动注册到一个Responsiory中。
这样会存在一些问题,比如你要扫描的class的package是一个父级的,比如com.xxxx。在公司这么多lib库下,这时候你遍历整个classpath真的要死人了
以前也有过类似的想法,自动扫描一个指定接口的实现或者指定后缀的名字,扫到class后自动注册到一个Responsiory中。
这样会存在一些问题,比如你要扫描的class的package是一个父级的,比如com.xxxx。在公司这么多lib库下,这时候你遍历整个classpath真的要死人了
这也是没办法的.为了灵活就必须牺牲一点效率.
反正这东西就在启动时扫描一次,应该可以接受.加载后就缓存吧.
12 楼
agapple
2010-11-17
undancer 写道
将配置文件写在/META-INF/services下,并使用java.util.ServiceLoader去加载。即使以后所有的实现不在同一个jar里也OK,比如java.sql.Driver等接口都是如此实现的。
查很多资料,不如多读一下API和常用jar的源码。国内资料很令人失望。
演示如下
查很多资料,不如多读一下API和常用jar的源码。国内资料很令人失望。
演示如下
public interface IFunction { //某个接口... }
public class IFunctionImpl implements IFunction { //该接口的实现... }
public class FooImpl implements IFunction { // 该接口的其他实现... }
#filename:META-INF/services/IFunction IFunctionImpl FooImpl
import java.util.Iterator; import java.util.ServiceLoader; public class Main { /** * @param args */ public static void main(String[] args) { // 配置文件写在META-INF/services/下,文件名为该接口名,没有文件后缀,一行一个实现,#表示该行为注释。 iterator(java.sql.Driver.class); /* * sun.jdbc.odbc.JdbcOdbcDriver@83cc67 * org.hsqldb.jdbc.JDBCDriver@e09713 */ iterator(IFunction.class); /* * IFunctionImpl@47b480 * FooImpl@10d448 */ } public static <T> void iterator(Class<T> service) { Iterator<T> iterator = ServiceLoader.load(service).iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
哈哈,/META-INF/services来说也是一个配置, Lz要的是最灵活的方法
以前也有过类似的想法,自动扫描一个指定接口的实现或者指定后缀的名字,扫到class后自动注册到一个Responsiory中。
这样会存在一些问题,比如你要扫描的class的package是一个父级的,比如com.xxxx。在公司这么多lib库下,这时候你遍历整个classpath真的要死人了
11 楼
undancer
2010-11-17
将配置文件写在/META-INF/services下,并使用java.util.ServiceLoader去加载。即使以后所有的实现不在同一个jar里也OK,比如java.sql.Driver等接口都是如此实现的。
查很多资料,不如多读一下API和常用jar的源码。国内资料很令人失望。
演示如下
查很多资料,不如多读一下API和常用jar的源码。国内资料很令人失望。
演示如下
public interface IFunction { //某个接口... }
public class IFunctionImpl implements IFunction { //该接口的实现... }
public class FooImpl implements IFunction { // 该接口的其他实现... }
#filename:META-INF/services/IFunction IFunctionImpl FooImpl
import java.util.Iterator; import java.util.ServiceLoader; public class Main { /** * @param args */ public static void main(String[] args) { // 配置文件写在META-INF/services/下,文件名为该接口名,没有文件后缀,一行一个实现,#表示该行为注释。 iterator(java.sql.Driver.class); /* * sun.jdbc.odbc.JdbcOdbcDriver@83cc67 * org.hsqldb.jdbc.JDBCDriver@e09713 */ iterator(IFunction.class); /* * IFunctionImpl@47b480 * FooImpl@10d448 */ } public static <T> void iterator(Class<T> service) { Iterator<T> iterator = ServiceLoader.load(service).iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
10 楼
i2534
2010-11-16
liquidthinker 写道
楼上,你太打击楼主的动手能力了
无所谓打击不打击了,习惯了.
9 楼
i2534
2010-11-16
219 写道
eclipse 中 ctrl+t 完事
...那脱离了eclipse呢?你别说到客户机器上装个eclipse,然后在里面运行项目...
8 楼
i2534
2010-11-16
ywlqi 写道
万一一个接口有两个实现怎么办?
这个就是要找多个实现的.
参考excel中的函数.
如果有同名函数实现,谁后加载算谁的.这个参考项目中同时存在两个不同版本的相同功能jar包的表现.
如tomcat下运行的web程序,在lib下放了个老版本的servlet.jar,会出现一些莫名其妙的错误.
7 楼
liquidthinker
2010-11-16
楼上,你太打击楼主的动手能力了
6 楼
219
2010-11-16
eclipse 中 ctrl+t 完事
5 楼
ywlqi
2010-11-16
万一一个接口有两个实现怎么办?
4 楼
i2534
2010-11-16
nuclearg 写道
这段代码我之前也写过,但是放到web容器就彻底不行了
究其原因,web容器会起一个自定义的ClassLoader来装载你的WEB-INF下面的东西,这个跟java.class.path一点关系都没有
这个问题困扰过我很长时间,最后结论是根据java的设计,不可能实现这个需求。
当然如果有谁想明白怎么做的话还望指教
究其原因,web容器会起一个自定义的ClassLoader来装载你的WEB-INF下面的东西,这个跟java.class.path一点关系都没有
这个问题困扰过我很长时间,最后结论是根据java的设计,不可能实现这个需求。
当然如果有谁想明白怎么做的话还望指教
我用的是j2se,不知道web上的表现.web的话,可以尝试查找WEB-INF的吧,我记得有方法可能得到这个路径的.其他的路径就不要管了.貌似也管不着...
3 楼
nuclearg
2010-11-16
这段代码我之前也写过,但是放到web容器就彻底不行了
究其原因,web容器会起一个自定义的ClassLoader来装载你的WEB-INF下面的东西,这个跟java.class.path一点关系都没有
这个问题困扰过我很长时间,最后结论是根据java的设计,不可能实现这个需求。
当然如果有谁想明白怎么做的话还望指教
究其原因,web容器会起一个自定义的ClassLoader来装载你的WEB-INF下面的东西,这个跟java.class.path一点关系都没有
这个问题困扰过我很长时间,最后结论是根据java的设计,不可能实现这个需求。
当然如果有谁想明白怎么做的话还望指教
2 楼
i2534
2010-11-15
limengchengg 写道
本人愚昧
找到了又怎么样呢
你是想要动态的找 动态的加载?
找到了又怎么样呢
你是想要动态的找 动态的加载?
...动态的找.省去了写配置文件而已.
是这样的场景;我写了接口,但是以后的实现的函数可能不是我写的,更可能和我这个jar包不是放在一起的.这样实现者值需要把实现的东西放在test.formalu.impl包或其子包下,然后导入到项目的classpath下,他就可以在公式里使用他实现的函数了.
1 楼
limengchengg
2010-11-15
本人愚昧
找到了又怎么样呢
你是想要动态的找 动态的加载?
找到了又怎么样呢
你是想要动态的找 动态的加载?
发表评论
-
公约数,公倍数和素数的简单计算
2012-04-01 16:08 1333为自己留作备份,省得用到的时候再去寻找 简单的计算最大公约数 ... -
java简单打印
2012-03-08 09:56 1234没什么,就是一个简单的打印,留作存档 publi ... -
httpclient4的封装
2012-01-06 15:11 4636没什么特别的,自己封装着用的. package cpcns. ... -
h2的baseDir
2011-11-11 16:38 1464使用h2 1.3.161.在web项目中.计划在Listene ... -
eclipse下自动打包项目并部署到web项目的lib下
2011-10-18 15:59 5119修改web项目的.settings下的org.eclipse. ... -
获取汉字的五笔,全拼和双拼的工具类
2011-10-10 15:51 2395如题,项目需要,首先可用的自然是pinyin4j. 在不考虑 ... -
五笔86和汉字对照表
2011-10-09 16:53 2536项目要用到汉字转拼音和五笔,拼音容易,使用pinyin4j. ... -
java System属性
2011-09-19 10:14 1388自定义 : java -Dname=value S ... -
log4j日志文件的相对路径
2011-09-01 10:51 6814一直没能很好的解决log4j的日志文件的保存路径.今天恰好又遇 ... -
Apache codec中的base64
2011-07-20 09:46 2289一直使用sun的base64,但是感觉不是很好,毕竟不是标准包 ... -
来,让我们一起画个印章吧
2011-07-04 14:52 4533这几天发现有哥们在介 ... -
svg中的arc转化为java中的arc
2011-05-27 15:31 2682最近项目需要解析svg中的path.直线和贝塞尔曲线都好办,唯 ... -
swing的拖拽(dnd)的简单实现
2011-03-28 10:18 2011这几天项目需要用到dnd,API比较麻烦.在网上找了很多,都只 ... -
自用的MD5计算工具
2011-03-11 15:45 1786/** * 检查输入流的MD5值是否符合.如果MD5为 ... -
用jsoup分析下载巨鲸的mp3
2011-02-25 15:37 1729这两天突然想听听杰克逊的歌.首选当然是巨鲸. 支持正版. ... -
获取子类的泛型参数
2011-01-27 16:03 1363用的时候不好找,今天看nutz的dao的源码看到了,摘出来备份 ... -
简单的通过注解运行的dao
2011-01-26 11:47 1796项目是个老项目,是个比较简单,但是编码比较凌乱的项目.数据库字 ... -
java模拟js的escape和unescape函数
2011-01-05 10:43 3470这个是在网上找的代码,然后修改了下.作用标题已经很明显了. ... -
自己写的多线程对象池
2010-12-10 16:53 1325/** * 排版器的一个公用接口 <br> ... -
apache poi读取excel中的颜色,真是坑爹啊
2010-12-01 16:23 16982工作原因,需要使用poi来读取excel中的所有内容. 其他 ...
相关推荐
本项目主要包括项目开发环境搭建、不同功能的类的设计、抽象类的设计、接口的设计、及其继承抽象类重写和接口实现类等具体功能的实现。 ●工程项目搭建与游戏初始化功能实现(2学时) ; ●动物城成员列表与动物信息...
3. **接口扫描**:为了找到实现特定接口的所有类,我们需要遍历类路径,加载每个类,并使用`Class.isAssignableFrom(Class<?> clazz)`检查该类是否实现了目标接口。`getInterfaces()`方法可以获取类实现的所有接口。...
在本文中,我们将深入探讨如何使用Apache Commons Discovery来查找可插拔接口的实现类。 Apache Commons Discovery的核心功能包括: 1. **服务注册**:允许程序向系统注册它们提供的服务。 2. **服务发现**:允许...
2. **实现接口**:创建一个类实现定义的接口,实现服务的具体逻辑。 ```java @WebService(endpointInterface = "com.example.MyWebService") public class MyWebServiceImpl implements MyWebService { @...
- `getAllAssignedClass()`方法通过遍历`getClasses()`返回的所有类,判断每个类是否是目标类(接口或父类)的子类或实现了目标接口,符合条件的加入到结果列表。 通过这段代码,我们可以获取到指定路径下所有实现...
本项目为Android项目中的一个功能模块,实现了在ListView中点击侧边字母导航栏进行A-Z的快速查找。此功能模块具有较高的实用性和可扩展性,可以满足用户在大量数据中快速定位的需求。 该模块的核心功能是通过监听...
然而,在日常开发中,有时我们需要快速定位到实现了某个接口的所有类,这时Eclipse的标准功能可能就显得不够便捷。为了弥补这一不足,有开发者专门制作了"追踪实现接口的Eclipse插件",使得这一操作变得更加简单。 ...
标题中的“eclipse查找文件、接口插件”指的是在Eclipse集成开发环境中使用特定功能或插件来快速定位和查找项目中的文件和接口。Eclipse作为一个强大的Java IDE,提供了多种方式来帮助开发者高效地管理代码。 在...
总结来说,这个项目展示了如何使用二叉查找树作为数据结构,实现一个简单但高效的单词信息检索系统。通过插入单词到树中,我们可以快速定位到特定单词;通过遍历树,我们可以查找满足特定条件的所有单词。这种方法在...
1. **查看实现接口方法的类:** - 在Eclipse中打开包含接口的源代码文件。 - 选中需要查找实现类的接口方法名。 - 右键选择`Open Implementation`选项。 - 如果存在多个实现类,插件会弹出一个选择列表供您挑选...
实现接口意味着一个类承诺实现接口中所有的抽象方法。在类声明中,我们使用`implements`关键字来实现接口: ```java public class MyClass implements MyInterface { public void method1() { // 实现方法1 } ...
通用IDispatch接口是COM(Component Object Model)组件模型中的一个重要接口,主要用于支持晚绑定(late ...在实际项目中,可能还需要考虑错误处理、线程安全以及性能优化等问题,确保IDispatch接口的高效稳定。
接口之间可以通过`extends`关键字实现接口的继承,形成接口的层次结构。了解这些关系有助于理解代码的组织结构,优化设计,并避免潜在的错误。 `.chm`文件是Windows平台下的一种帮助文件格式,它将HTML、图像和其他...
在Vue项目中实现接口统一管理的一个常见做法是在项目的`src`目录下创建一个名为`apis`的文件夹。在这个文件夹内,可以创建一个`http.js`文件,用于封装axios库以定义所有接口请求。这个封装后的函数可以提供统一的...
2. **work19.cpp、work19.h**:这两个文件可能是项目的工作文件和头文件,其中`work19.cpp`包含了实现的函数和类定义,而`work19.h`可能包含了对外部的接口声明,便于其他模块调用这些查找算法。 3. **work19.dsp、...
本项目以C语言实现了一个英语词典的索引查找功能,旨在帮助用户快速查找并定位单词。这个实现不仅涉及到C语言的基础编程,还涉及到了数据结构与算法中的索引技术,具有很高的学习价值。 首先,我们要理解索引查找的...
学习这个示例,开发者可以了解如何在实际项目中设计和实现一个查找类型类的浏览器应用程序,同时加深对C#和VB编程的理解,以及数据结构和算法的应用。对于想要提高软件开发能力的人来说,这是一个很好的实践机会。
至于“IPSeek”这个文件或项目,很可能是实现上述功能的一个具体工具或库。它可能包含了一系列用于查询IP地址信息的函数或类,或者是一个完整的IP查询服务的客户端程序。用户可以通过调用这个库的API,轻松地获取到...
总的来说,Struts2接口文档是学习和使用Struts2框架不可或缺的工具,它能帮助开发者高效地理解和使用框架提供的各种组件和接口,提升开发效率,减少错误,并有助于深入理解MVC模式在实际项目中的应用。通过仔细研读...
本教程将深入探讨三种重要的数据结构:栈、队列和二叉查找树,并介绍如何在C++中实现它们。 首先,栈(Stack)是一种后进先出(LIFO)的数据结构。它的工作原理类似于图书馆的书架,新放入的书籍(元素)会被放在最...