2010年3月14日

例子下载在此

最近搞了个小实验,发现Eclipse 插件的类加载的一个问题。Eclipse使用Equinox实现OSGi的框架,可以在插件的配置中确定哪些类expose出去,哪些类不能为外部所见。我发现的问题是,可以通过ClassLoader绕过这个限制,在外部插件中加载到插件里那些不为外部所见的类,并且能够创建类的实例,可以通过反射调用其方法(当然,如果被加载的类实现了某些接口,也可以通过接口的引用直接调用相应的方法)。

为了演示这个问题,先在eclipse中创建一个插件UtilityLibrary

其中utilitylibrary.expose包中的类会暴露给外部,而utilitylibrary.hide包中的类不会暴露给外部。在MANIFEST.MF中增加这个设置:


VisiableClassVisiableClass类的内容很简单:
package utilitylibrary.expose;

public class VisiableClass {
    
public VisiableClass() {
        System.out.println(
"This is VisiableClass");
    }

    
public String getMessage() {
        
return "From VisiableClass:\r\n"
                
+ this.getClass().getClassLoader().toString() + "\t";
    }
}

package utilitylibrary.hide;

public class InvisiableClass {
    
public InvisiableClass() {
        System.out.println(
"InvisiableClass");
    }

    
public String getMessage() {
        
return "From InvisiableClass:\r\n"
                
+ this.getClass().getClassLoader().toString() + "\t";
    }
}


其实主要就是打印出相应的信息。类代码几乎是一样的。

下面创建另一个插件UsePlugin,依赖并使用UtilityLibrary中的类。插件其实就是Eclipse自带的Hello World程序,它会在eclipse 的toolbar上增加一个按钮,点击后会弹出一个MessageBox。好,MessageBox上显示的就是从UtilityLibrary中类的方法的返回值。首先增加插件依赖关系:


在SampleAction中的Run方法里,如果直接使用InvisiableClass,插件完全找不到这个类,修改建议里面建议expose这个类:


当然,使用VisiableClass是没问题的。下面通过VisiableClass来将InvisiableClass拽出来,SampleAction类的源代码如下,只要关心run方法就可以了:

package useplugin.actions;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

import utilitylibrary.expose.VisiableClass;

/**
 * Our sample action implements workbench action delegate. The action proxy will
 * be created by the workbench and shown in the UI. When the user tries to use
 * the action, this delegate will be created and execution will be delegated to
 * it.
 * 
 * 
@see IWorkbenchWindowActionDelegate
 
*/
public class SampleAction implements IWorkbenchWindowActionDelegate {
    
private IWorkbenchWindow window;

    
/**
     * The constructor.
     
*/
    
public SampleAction() {
    }

    
/**
     * The action has been activated. The argument of the method represents the
     * 'real' action sitting in the workbench UI.
     * 
     * 
@see IWorkbenchWindowActionDelegate#run
     
*/
    
public void run(IAction action) {
        
try {
            Class
<?> clazz = VisiableClass.class.getClassLoader().loadClass(
                    
"utilitylibrary.hide.InvisiableClass");
            Object obj 
= clazz.newInstance();
            Method method 
= clazz.getMethod("getMessage");
            Object ret 
= method.invoke(obj, new Object[] {});
            System.out.println(ret);
            MessageDialog.openInformation(window.getShell(), 
"UsePlugin", ret
                    .toString());
        } 
catch (ClassNotFoundException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (InstantiationException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (IllegalAccessException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (SecurityException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (NoSuchMethodException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (IllegalArgumentException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
catch (InvocationTargetException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    
/**
     * Selection in the workbench has been changed. We can change the state of
     * the 'real' action here if we want, but this can only happen after the
     * delegate has been created.
     * 
     * 
@see IWorkbenchWindowActionDelegate#selectionChanged
     
*/
    
public void selectionChanged(IAction action, ISelection selection) {
    }

    
/**
     * We can use this method to dispose of any system resources we previously
     * allocated.
     * 
     * 
@see IWorkbenchWindowActionDelegate#dispose
     
*/
    
public void dispose() {
    }

    
/**
     * We will cache window object in order to be able to provide parent shell
     * for the message dialog.
     * 
     * 
@see IWorkbenchWindowActionDelegate#init
     
*/
    
public void init(IWorkbenchWindow window) {
        
this.window = window;
    }
}


在run方法里面,直接使用VisiableClass.class.getClassLoader().loadClass("utilitylibrary.hide.InvisiableClass");来加载本不应该被外部所见的Invisiable类。因为在Eclipse中,每个插件使用一个ClassLoader,所以用来加载VisiableClass类的ClassLoader也同样负责加载在同一个插件中的InvisiableClass类。这样InvisiableClass就在插件外部被加载成功了。类加载成功后,剩下的事情就是顺水推舟了,创建个实例然后使用反射调用相应的方法。
程序运行的时候,点击toolbar上那个button,会弹出如下对话框:


程序运行也没啥错误。


问题分析:
其实我觉得这个问题是很难绕过去的。对于同一个插件,因为内部的类需要互相引用和互相使用,所以必须使用同一个类加载器来加载。所以,这个插件只要expose出来一个包,那么外部的插件就可以通过包中的任何一个类来得到加载这个插件中的类的类加载器,然后就可以通过reflect爱做啥做啥了。

换一个角度可能更好理解这个问题为什么难以绕过去。假设VisiableClass需要用到InvisiableClass,虽然InvisiableClass没有暴露出来,但是在正常的使用VisiableClass的时候,需要先加载VisiableClass类,而加载VisiableClass的时候JVM就会隐式的加载InvisiableClass。这个过程和例子里现式的加载InvisiableClass没啥本质不同。也就是说,从ClassLoader的角度,很难判断一个类的加载是正常的代码还是为了突破bundle的访问限制——它们都是在执行run方法时发生的类加载行为。

或者是我有什么地方没设置好?求解答。例子下载在此

posted @ 2010-05-17 12:09 深夜两点 阅读(4777) | 评论 (8)编辑 收藏

宅能量终于爆发了,书终于出版了。China Pub有售http://www.china-pub.com/196571

posted @ 2010-04-27 20:47 深夜两点 阅读(1660) | 评论 (1)编辑 收藏

在设计一个多线程程序的时候,首先要考虑好线程模型是怎样的。设计线程模型的时候可以有多个考虑,比如使用线程池,使用多个线程处理任务,或者使用类似AWT/Swing中事件处理机制那样,使用单个线程处理同一类的任务。

posted @ 2010-04-26 16:33 深夜两点 阅读(234) | 评论 (0)编辑 收藏

rt

posted @ 2010-04-11 11:21 深夜两点 阅读(233) | 评论 (0)编辑 收藏

自己写的一个小程序,做个视频冒充一下技术宅……


程序经多次优化,终于能够达到一个可以接受的性能了……莫言Java无效率,其实重要的还是要精雕细琢。至 少就绘制Julia Set而言,我这个程序比我见过的几个cpp版本的要快的多。
项目主页地址:http://code.google.com/p/juliasetcreator/
程序下载地址:http://code.google.com/p/juliasetcreator/downloads/list

posted @ 2010-03-20 17:25 深夜两点 阅读(2616) | 评论 (2)编辑 收藏

转自http://static.icybear.net/%5BCN%5DProgrammer%20competency%20matrix.htm

[译文]程序员能力矩阵 Programmer Competency Matrix

注意:每个层次的知识都是渐增的,位于层次n,也蕴涵了你需了解所有低于层次n的 知识。
计算机科学 Computer Science
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
数据结构 不知道数组和链表的差异 能够解释和使用数组, 链表,字典等,并且能够用于实际的编程任务。 了解基本数据结构时间和空间的折中,比如数组vs 链表,能够解释如何实现哈希表和处理冲突,了解优先队列及其实现。 高等的数据结构的知识,比如B-树、二项堆、斐波那契堆、AVL 树、红黑树、伸展树、跳跃表以及前缀树等。
算法 不能够找出一个数组各数的平均值(这令人难以置信,但是我的确在应聘者 中遇到过) 基本的排序,搜索和数据的遍历和检索算法。 树,图,简单的贪婪算法和分而治之算法,能够适度了解矩阵该 层的含义。 能够辨识和编写动态规划方案,良好的图算法知识,良好的数值估算的知识,能够辨别NP问题等。 Working with someone who has a good topcoder ranking would be an unbelievable piece of luck!
编程体系 不知道何为编译器、链接器和解释器。 对编译 器、链接器、解释器有基本的了解。知道什么是汇编代码以及在硬件层如何工作。有一些虚拟内存和分页知识。 了解内核模式vs用户模式, 多线程,同步原语以及它们如何实现,能够阅读汇编代码。了解网络如何工作,了解网络协议和socket级别编程。 了解整个程序堆栈、 硬件(CPU+内存+中断+微码)、二进制代码、汇编、静态和动态链接、编码、解释、JIT(just-in-time)编译、内存碎片回收、堆、栈、存 储器编址…
软件工程 Software Engineering
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
源码版本控制 通过日期备份文件夹 VSS和初级的 CVS/SVN用户 熟练地使用CVS和SVN特性。知道如何分支和归并,使用程序库补丁安装特性等 有分布式VCS 系统的知识。尝试过Bzr/Mercurial/Darcs/Git
自动化编译 只知道在IDE下编译 知道如何编译在命令行 下编译系统 能够安装一个脚本构建基本的系统 能够安装一个脚本来构建系统并且归档,安装程序,生成发布记录和给源 码控制中的代码分配标签。
自动化测试 认为所有的测试都是测试员的工作。 能够编写 自动化的单元测试,能够为正在编写的代码提出良好的测试用例。 按照TDD (Test Driven Development)方式编写代码。 了解并且能够有效自动化安装,载入/性能和UI测试
程序设计 Programming
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
问题分解 只有直线式的代码,通过复制粘贴来复用 能够把 问题分散到多个函数中 能够想出可复用的函数/对象来解决大题的问题 使用适宜的数据结构和算法,写出通用的/面向 对象的代码来封装问题的易改变的层面。
系统分解 N想不出比单一的文件/类更好的层面 如果不在 同一平台或没采用相同的技术,能够把问题空间和设计方案分解。 能够设计跨技术/平台的系统。 能够在多个产品线和 与外部体系一体化中虚拟化和设计复制的系统。同时也能够设计支持系统监视、报告、故障恢复等。
交流 不能向同伴表达想法/主意。匮乏拼写和语法的能力。 同 伴能了解你在说什么。有良好的拼写和语法能力。 能够和同伴进行高效的交流 能够使用清晰的方式了解和交流想法/设计 /主意/细则,能适应每种环境的交流 This is an often under rated but very critical criteria for judging a programmer. With the increase in outsourcing of programming tasks to places where English is not the native tongue this issue has become more prominent. I know of several projects that failed because the programmers could not understand what the intent of the communication was.
同一文件中代码组织 同一文件中组织没有依据 按照逻辑 性或者易接近的方法 代码分块和对于其他源文件来说是易于是释,引用其他源文件时有良好的注释 文档头部有许可声 明,总结,良好的注释,一致的空格缩进。文档外观美观。
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
跨文件代码组织 没够想过给代码跨文件组织 相关文件按文件 夹分组 每个物理文件都有独立的目的,比如一个类的定义,一个特性的实现等。 代码在物理层组织紧密,在文件名上与 设计和外观相匹配,可以通过文件分布方式洞察设计理念。
源码树组织 一切都放在一个文件夹内 初步地将代码分散进 对应逻辑的文件夹。 没有循环依赖,二进制文件,库,文档,构建,第三方的代码都组织进合适的文件夹内。 源码树的 物理布局与逻辑层次、组织方式相匹配。可以通过目录名称和组织方式洞察设计理念。 The difference between this and the previous item is in the scale of organization, source tree organization relates to the entire set of artifacts that define the system.
代码可读性 单音节的名称 (在国内应该是那些类似用汉语拼音命名的习惯) 对文件、变量、类、方法等,有良好的命名。 没有长函数、注释解释不常规的代码,bug修复,代码假设。 代 码假设验证使用断言,自然的代码流,没有深层嵌套的条件和方法
防御性编码 不知道这个概念 检查代码中所有的参数,对关键 的假设进行断言 确保检查了返回值和使代码失败的异常。 有自己的库来帮助防御性编程、编写单元测试模拟故障
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
错误处理 只给乐观的情形编码 基本的代码错误处理,抛出 异常/生成错误 确保错误/异常留在程序中有良好的状态,资源,连接,内存都有被合适的清理。 在编码之前察觉可能 出现的异常,在代码的所有层次中维持一致性的异常处理策略,提出整个系统的错误处理准则。
IDE IDE大部分用来进行文本编辑 了解其周围的接 口,能够高效地通过菜单来使用IDE 了解最常操作的键盘快捷键 编写自定义宏
API 需要频繁地查阅文档 把最频繁使用的API记在脑 子里 广阔且深入的API知识。 为了使实际任务中常用API使用更加便捷,编写过API的上层库,填补API之间 的缺口。 E.g. of API can be Java library, .net framework or the custom API for the application
框架 没有使用过主平台外的任何框架 听过但没用过平台下 流行的可用框架 在专业的职位中使用过一个以上的框架,通晓各框架的特色。 某框架的作者
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
需求分析 接受给定的需求和代码规格 能对规格的遗漏提出 疑问 了解全面情况,提出需要被规格化的整体范围。 能够提出更好的可选方案,根据经验的浮现给出需求
脚本 不具备脚本工具的知识 批处理文件/shell脚本 Perl/Python/Ruby/VBScript/Powershell 写过并且发表过可重用的代码
数据库 认为Excel就是数据库 知道基本的数据库概 念,规范化、ACID(原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)、事务化,能 够写简单的select语句 能够牢记在运行时必要查询中设计良好的规范化数据库模式, 精通用户视图,存储过程,触发器和用户定义类型。知道聚集与非聚集索引之间的差异。精通使用ORM(Object Relational Mapping对象关系映射)工具 能做基本的数据库管理,性能优化,索引优化,编写高级的select查询,能够使用相关sql来替 换游标,理解数据内部的存储,了解如何镜像、复制数据库。知道两段数据提交如何工作
经验 Experience
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
专业语言经验 命令式语言和面向对象语言 命令式语言,面向对象语言和说明型语言(SQL),如果了解静态类型vs动态类型,弱类型vs强类型则有加分 函数式语言,如果了解延 缓求值,局部套用函数,延续则有加分 并发语言(Erlang, Oz) 逻辑语言(Prolog)
专业平台经验 1 2-3 4-5 6+
专业经验年龄 1 2-5 6-9 10+
领域知识 没有该领域的知识 在该领域中曾经至少为一个 产品工作过 在同一领域中为多个产品工作过 领域专家。在该领域设计和实现数种产品/方案。精通该领域使用的标准条款 和协议
学识 Knowledge
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
工具知识 仅限于主要的IDE(VS.Net, Eclipse等) 知 道一些流行和标准工具的备选方案 对编辑器、调试器、IDE、开源的备选方案有很好的了解。比如某人了解大多数Scott Hanselman的威力工具列表中的工具,使用过ORM工具。 实际地编写过工具和脚本,如果这些被发布则有加分
语言接触 命令式语言和面向对象语言 命令式语言、面向对象 语言和说明型语言(SQL),如果了解静态类型vs动态类型、弱类型vs强类型则有加分 函数式语言,如果了解延缓求值、局部套用函 数、continuations (源于scheme中的一种高级控制结构)则有加分 并发语言(Erlang, Oz) 逻辑语言(Prolog)
代码库知识 从来没有查询过代码库 基本的代码层知识,了 解如果构建系统 良好的代码库工作知识,实现过几次bug修复或者完成了一些细小的特性 实现了代码库中多个大型特 性,能够轻松地将多数特性的需求变更具体化,从容地处理bug修复。
下一代技术知识 从来没听说过即将到来的技术 听说过某领 域即将到来的技术 下载过alpha preview/CTP/beta版本,并且读过一些文章和手册 试用过预览 版而且实际地构建过某物,如果共享给其他人的话则有加分
  2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments
平台内部 对平台内部毫无所知 有平台基本的内部工作的 知识 深度的平台内部知识,能够设想平台如何将程序转换成可执行代码。 编写过增强平台或者为其平台内部提供信息的 工具。比如,反汇编工具,反编译工具,调试工具等。
书籍 菜鸟系列,21天系列,24小时系列,蠢货系列... 《代 码大全》,《别让我思考》, 《精通正则表达式》 《设计模式》,《人件》,《代码珠玑》,《算法设计手册》,《程序员修炼之道》, 《人月神话》 《计算机程序设计与解释》,《事务处理:概念与技术》,《计算机程序设计模型》,《计算机程序设计艺术》,《数据库系统 导论》 C.J Date版,《Thinking Forth》 ,《Little Schemer》(没找到其中译本)
博客 听过但是从来抽不出空去接触 阅读一些科技/编程 /软件工程的博客,并且经常的收听一些播客 维护一些博客的链接,收集博主分享的有用的文章和工具 维护一个在编程方 面,分享有个人见解和思考的博客
Creative Commons License
程序员能力矩阵 by XGuru is licensed under a Creative Commons 署名-非商业性使用-相同方式共享 2.5 中国大陆 License. 原文请看 这 里
Thanks to bearice for debugging.
Thanks to John Haugeland for a reformatting of it that works much more nicely on the web.

posted @ 2010-03-14 23:35 深夜两点 阅读(231) | 评论 (0)编辑 收藏