- 浏览: 179406 次
- 性别:
- 来自: 北京
最新评论
-
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 1271为自己留作备份,省得用到的时候再去寻找 简单的计算最大公约数 ... -
java简单打印
2012-03-08 09:56 1188没什么,就是一个简单的打印,留作存档 publi ... -
httpclient4的封装
2012-01-06 15:11 4564没什么特别的,自己封装着用的. package cpcns. ... -
h2的baseDir
2011-11-11 16:38 1411使用h2 1.3.161.在web项目中.计划在Listene ... -
eclipse下自动打包项目并部署到web项目的lib下
2011-10-18 15:59 5063修改web项目的.settings下的org.eclipse. ... -
获取汉字的五笔,全拼和双拼的工具类
2011-10-10 15:51 2284如题,项目需要,首先可用的自然是pinyin4j. 在不考虑 ... -
五笔86和汉字对照表
2011-10-09 16:53 2473项目要用到汉字转拼音和五笔,拼音容易,使用pinyin4j. ... -
java System属性
2011-09-19 10:14 1336自定义 : java -Dname=value S ... -
log4j日志文件的相对路径
2011-09-01 10:51 6758一直没能很好的解决log4j的日志文件的保存路径.今天恰好又遇 ... -
Apache codec中的base64
2011-07-20 09:46 2241一直使用sun的base64,但是感觉不是很好,毕竟不是标准包 ... -
来,让我们一起画个印章吧
2011-07-04 14:52 4411这几天发现有哥们在介 ... -
svg中的arc转化为java中的arc
2011-05-27 15:31 2629最近项目需要解析svg中的path.直线和贝塞尔曲线都好办,唯 ... -
swing的拖拽(dnd)的简单实现
2011-03-28 10:18 1953这几天项目需要用到dnd,API比较麻烦.在网上找了很多,都只 ... -
自用的MD5计算工具
2011-03-11 15:45 1737/** * 检查输入流的MD5值是否符合.如果MD5为 ... -
用jsoup分析下载巨鲸的mp3
2011-02-25 15:37 1678这两天突然想听听杰克逊的歌.首选当然是巨鲸. 支持正版. ... -
获取子类的泛型参数
2011-01-27 16:03 1304用的时候不好找,今天看nutz的dao的源码看到了,摘出来备份 ... -
简单的通过注解运行的dao
2011-01-26 11:47 1714项目是个老项目,是个比较简单,但是编码比较凌乱的项目.数据库字 ... -
java模拟js的escape和unescape函数
2011-01-05 10:43 3419这个是在网上找的代码,然后修改了下.作用标题已经很明显了. ... -
自己写的多线程对象池
2010-12-10 16:53 1273/** * 排版器的一个公用接口 <br> ... -
apache poi读取excel中的颜色,真是坑爹啊
2010-12-01 16:23 16840工作原因,需要使用poi来读取excel中的所有内容. 其他 ...
相关推荐
本项目主要包括项目开发环境搭建、不同功能的类的设计、抽象类的设计、接口的设计、及其继承抽象类重写和接口实现类等具体功能的实现。 ●工程项目搭建与游戏初始化功能实现(2学时) ; ●动物城成员列表与动物信息...
本项目为Android项目中的一个功能模块,实现了在ListView中点击侧边字母导航栏进行A-Z的快速查找。此功能模块具有较高的实用性和可扩展性,可以满足用户在大量数据中快速定位的需求。 该模块的核心功能是通过监听...
做项目时,要在原有项目的基础增加国际化版本,查找和替换中文成了必做的工作,为了加快工作速度,所有的重复性工作都交给程序来处理,自己只做核心工作,经过自己的编码和实践应用,写了一套配合自己工作的程序,...
5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源介绍】 基于C++实现的职工管理系统源码+设计报告+程序说明文档.zip 1、管理系统需求 2、创建项目 2.1 创建项目 2.2 添加文件 3、创建管理类 3.1...
29.3.2 实现数据连接操作(DAO)的实现类 29.3.3 实现数据连接操作(DAO)的代理类 29.3.4 实现数据连接操作(DAO)的工厂类 29.4 人员信息管理项目——服务层和表示层 29.4.1 人员信息管理项目的服务层 29.4.2 人员...
实例193 获取网络中所有工作组名称 实例194 列出指定工作组中的所有计算机名 实例195 监测当前网络连接状态 实例196 使用udp协议设计聊天室 第18章 注册表技术 实例197 禁止运行注册表 实例198 使应用程序开机自动...
本项目是基于个人喜好及实际开发需求进行编写和设计的,主要功能是完成了对微信企业号API的封装,目前还在不断完善中,通过调用本项目的类库和函数,可以实现调用微信企业号API,降低了开发成本,开发者可以不用再...
本项目是基于个人喜好及实际开发需求进行编写和设计的,主要功能是完成了对微信企业号API的封装,目前还在不断完善中,通过调用本项目的类库和函数,可以实现调用微信企业号API,降低了开发成本,开发者可以不用再...
本项目基于Spring-data-neo4j,整合图存数据库Noe4j, 实现增删改查的功能。主要功能包括: 1.基于spring-data-neo4j 3.2.0通过REST远程连接Neo4j服务器,并非嵌入式连接; 2.创建接口用于创建一个简单的图存数据库...
模块功能说明 数据结构模块:该模块实现了基本的数据结构,为上层模块提供...服务接口模块:该模块实现了程序的主要功能,在数据结构模块和数据模型模块的基础上,对于程序的所有功能进行了具体实现,利用辅助工具模块
商品展示模块实现了依照分类进行查找显示商品功能,并实现了组建化分页。 购物车模块实现了添加购物、修改购物信息、删除货品、恢复删除的功能。 订单模块实现了用户地址添加、回填,生成订单,购物车清空等功能。 ...
> - 本项目使用了类模板进行编程;实现了对数据的增删改查,以及数据落盘和文件加载数据等功能;对数据库性能进行了简单的压力测试,采用了随机写读的方法,在不同数据规模下获得了每秒可处理请求数(QPS)指标。 > ...
4.3.5 查找文件、遍历指定目录下的文件和子目录 100 4.3.6 递归遍历目录树 103 4.3.7 获取、设置文件属性和时间 105 4.4 内存映射文件 110 4.4.1 使用Mapping File提高文件读写的效率 110 4.4.2 通过...
6.3.5 创建Web项目中的Java类文件 92 6.3.6 发布和运行Web项目 94 6.4 Web应用实例:登录系统 96 6.5 本章小结 102 第7章 数据库应用程序的开发及应用 103 7.1 MySQL数据库的安装与配置 103 7.2 MyEclipse中的...
基于python+opencv实现的欢乐斗地主记牌器系统源码+项目说明(数字图像处理课程设计).zip 把图像分成上中下三块,分别是地主牌、对手出牌、自己手牌,计算出大致区域(直接切片选取) 读取图片,转为SHV提取白色区域...
文本处理:使用Java提供的字符串处理功能,实现文本编辑和查找替换功能。 语法高亮:通过正则表达式匹配文本中的关键词,并设置相应的文本颜色实现语法高亮显示。 扩展性与定制性: 插件支持:设计插件接口,允许...
项目特色 ... 用户在找书,阅读的过程中,应用会自动记录用户的查找、阅读历史,并在用户再次进入应用时智能提醒用户是否回到上次阅读的状态。 完美的实现了多平台同步使用。 该应用实现了电脑、手机、平
接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的...