BlueDavy

构客网首页  博客  论坛

 
  SOA我有话说
  本文的标签
OSGI (收录168篇)Equinox (收录25篇)
  用户信息
 
帐号:  新手必读
密码: 保存密码
 
  分类列表
全部类别(221 篇)
我的文章(10 篇)
RIAWork(10 篇)
Java(36 篇)
Javascript(8 篇)
OSGi、SCA(60 篇)
Plugin Architecture(9 篇)
Workflow(5 篇)
业界随想(21 篇)
数据集成(8 篇)
系统设计(27 篇)
软件工程(27 篇)
  按月归档
2005年-07月(20 篇)
2005年-11月(25 篇)
2006年-04月(83 篇)
2006年-12月(19 篇)
2007年-07月(24 篇)
2007年-11月(10 篇)
2008年-01月(23 篇)
2008年-11月(3 篇)
2009年-02月(13 篇)
2009年-11月(1 篇)
  SOA2007 - SOA实践
我们何时迈向SOA
——SOA在中国的整体发展现状究竟如何?
我们如何迈向SOA
——中国企业如何迈出实施SOA的第一步?
我们应采用何种技术
——SOA国际标准SCA/SDO的具体内涵?
我们还需要何种技能
——SOA将如何改变系统架构设计以及项目管理过程?

实现ClassLoaderDelegateHook控制Equinox的类加载

发布时间:2009年11月16日 作者:BlueDavy

阅读次数:28119次 类别:我的文章 永久链接 Trackback 
参加SOA我有话说
Equinox的设计非常经典,其在扩展方面提供了很多的支持,同样包括类加载方面的控制,除了通过标准的org.osgi.framework.bootdelegation以及equinox提供的osgi.parentClassLoader这两个属性来简单的控制类加载之外,还可通过实现ClassLoaderDelegateHook来更为灵活的控制类加载。

对Equinox代码进行分析,想让扩展的ClassLoaderDelegateHook起作用,首先要能够让这个ClassLoaderDelegateHook注册到Equinox中,Equinox在进行类加载的过程中会调用searchHooks来寻找ClassLoaderDelegateHook的实现,寻找的方法为获取bundle.framework.delegateHooks属性,而framework中的delegateHooks属性是在initialize时通过adaptor的getHookRegistry()的getClassLoaderDelegateHooks()方法来获取的,并且framework没有提供setDelegateHooks或addDelegateHook这样的方法,所以没办法直接设置,从这来看,是否意味着只需要在framework initialize之前通过adaptor的getHookRegistry来注册ClassLoaderDelegateHook就可以呢,继续看BaseAdaptor类,恩,确实通过adaptor的getHookRegistry可以来增加ClassLoaderDelegateHook,但由于启动过程是在EclipseStarter里面完成的,BaseAdaptor是在启动的代码里创建的,这样就没办法保证在framework initialize之前增加自己实现的ClassLoaderDelegateHook了,查看EclipseStarter代码,幸运的是可以通过设置osgi.adaptor属性来指定Adaptor类的名称,于是决定继承BaseAdaptor,在构造器中创建通过获取HookRegistry来增加自行实现的ClassLoaderDelegateHook类,这里还有个小问题,BaseAdaptor在构造器中创建HookRegistry后调用了其initiliaze方法,而HookRegistry在initialize方法中将其私有的一个readonly属性设置为了true,这导致的后果是无法在这之后增加ClassLoaderDelegateHook,如增加,则会抛出:IllegalStateException,错误信息为:Cannot add hooks dynamically,因此,在调用addClassLoaderDelegateHook之前必须通过反射先将HookRegistry中的readonly属性设置为false,按照上面的方法,实现的关键代码如下:

// 设置自行实现的Adaptor类名
FrameworkProperties.setProperty(EclipseStarter.PROP_ADAPTOR, CustomAdaptor.class.getName());

public class CustomAdaptor extends BaseAdaptor {

    
public CustomAdaptor(String[] args) {
        
super(args);
        HookRegistry hookRegistry
=getHookRegistry();
        
try{
            Field readOnlyField
=HookRegistry.class.getDeclaredField("readonly");
            readOnlyField.setAccessible(
true);
            readOnlyField.setBoolean(hookRegistry, 
false);
            hookRegistry.addClassLoaderDelegateHook(自行实现的ClassLoaderDelegateHook类);
        }
        
catch(Exception e){
            
e.printStackTrace();
        }
    }

}

ClassLoaderDelegateHook类则可根据自己的需求进行实现,在这个类中可灵活控制类加载的过程,接口中控制类加载的方法说明如下:
preFindClass 
在Equinox判断是否需要从boot classloader中加载后,就会尝试调用ClassLoaderDelegateHook的这个方法来加载类,如此方法抛出ClassNotFoundException,则终止类查找,因此,如果希望Hook中加载不到时继续执行Equinox的类加载的话,在Hook中就不要抛出ClassNotFoundException。
postFindClass
在Equinox已经尝试过从Bundle的import-package、require-bundle、bundle-classpath以及dynamicimport-package中加载后,会尝试调用ClassLoaderDelegateHook的这个方法来加载类。

上面的方法并不优雅,从Equinox设计了Hook来看,不可能要这么复杂才能增加一个Hook,于是继续回头看代码,不负期望,在HookRegistry的initialize方法中,会去加载配置的osgi.hook.configurators、osgi.hook.configurators.include和osgi.hook.configurators.exclude三个属性值或指定的hookconfigurators.properties文件,最后合并形成需要加载执行的HookConfigurator类,从上面的代码来看,只用在自行实现的ClassLoaderDelegateHook类上再增加HookConfigurator接口的实现,并将其注册到HookRegistry中,最后在osgi.hook.configurators中配置这个类即可,由于equinox内部已经有配置了一些HookConfigurator的,因此此处需要把equinox jar中的hookconfigurators.properties里面配置的hook.configurators也增加进去,要么就是把自己需要增加的HookConfigurator加到equinox jar的hookconfigurators.properties中,这种方法就优雅很多了,按照这种方法实现后的关键代码如下:

// 设置需要装载的HookConfigurator的实现类
FrameworkProperties.setProperty("osgi.hook.configurators", CustomClassLoaderDelegate.class.getName());

public class CustomClassLoaderDelegate implements ClassLoaderDelegateHook,HookConfigurator {

    
public Class postFindClass(String name, BundleClassLoader classloader,
            BundleData data) 
throws ClassNotFoundException {
        
// 自行实现
    }
    

    
public URL preFindResource(String name, BundleClassLoader classloader,
            BundleData data) 
throws FileNotFoundException {
        
// 自行实现
    }

    
public Enumeration preFindResources(String name, BundleClassLoader classloader,
            BundleData data) 
throws FileNotFoundException {
        
// 自行实现
    }

    
public String postFindLibrary(String arg0, BundleClassLoader arg1,
            BundleData arg2) {
        
// 自行实现
    }

    
public URL postFindResource(String arg0, BundleClassLoader arg1,
            BundleData arg2) 
throws FileNotFoundException {
        
// 自行实现
    }

    
public Enumeration postFindResources(String arg0, BundleClassLoader arg1,
            BundleData arg2) 
throws FileNotFoundException {
        
// 自行实现
    }

    
public Class preFindClass(String arg0, BundleClassLoader arg1,
            BundleData arg2) 
throws ClassNotFoundException {
        
// 自行实现
    }

    
public String preFindLibrary(String arg0, BundleClassLoader arg1,
            BundleData arg2) 
throws FileNotFoundException {
        
// 自行实现
    }

    
public void addHooks(HookRegistry registry) {
        registry.addClassLoaderDelegateHook(
this);
    }

}

ps: 在《OSGi原理与最佳实践》中没来得及写上这部分,就在这篇blog上写了。

 评论 查看全部评论