论坛首页 Java版

有关于classloader的思考(或者说是困惑)

浏览 8496 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2006-07-13
想设计个比较大的项目(MIS类型的,可以认为是个财务,人力资源,供应链,CRM的杂交体),里面有若干模块,将来还会有更多的模块。
  现在在架构上有如下需求:
      1。有一个核心模块,作为各个模块的基础,负责调用各个具体模块,负责处理诸如事务,权限等问题。
      2。各个模块要保持独立性,也就是说,各模块在除核心模块以外不必考虑其他模块是否存在就可以编译,测试。(但不一定能够实际运行,因为有些模块在业务上是耦合紧密的,比如绝大部分模块在业务上都依赖基本档案模块,但在程序上不应该依赖)。
         独立性还包括这样的需求。各个模块引用的第三方项目互不干扰。比如A模块引用了Spring2.0,B模块引用了Spring1.1,它们都能正常运行。甚至两个模块可以有两个完全相同的类的定义。
      3。但各个模块又有相关性,比如采购模块需要财务模块为其提供接口来根据发票生成凭证,生产制造模块需要采购模块给其提供接口生成采购订单。
      4。实现以上需求的基础上,还要保持开发的便利性。
     
         
  熟悉classloader的结构,粗看一下觉得设计出符合上面需求的架构不算难。
        无非就是设计出一个ClassLoader的树形结构:
       
   [code:1]     java system classloader
            |
            |
            |
        核心模块classloader
            |
            |
            |
        具体各个模块有自己的一个classloader.[/code:1]
 
 
 
  各个模块的classloader都以核心模块为parent classloader,他们都拥有自己模块的类路径。
  大家想被别的模块访问的东西都打成jar直接扔到核心模块的类路径里去。
 
  出现问题了如下:
 
  1。核心模块本身的功能实现就需要用到很多第三方的包:hibernate,acegi,spring等等。
      也就是说,核心模块本身已经污染了其他的各个具体模块,而除了hibernate以外,其他模块实际上不需要核心模块“附送”的其他第三方库。
     
  2。各模块的公共接口怎么暴露?
      假如A模块有个HelloService类希望暴露给其它模块。
     
     [code:1] import someOtherClass
      public HelloService extend AbstractXXXXService
      {
            public HelloObj sayHello(HelloParam1 p1,HelloParam2 p2)
            {
                  //do anything
                  return new HelloObj();
            }
      }[/code:1]
     
      那需要把什么给放到核心模块里才能被其它模块正常访问呢?
      包括: someOtherClass
            AbstractXXXXService
            HelloObj
            HelloParam1
            HelloParam2
           
            以及他们本身再引用的类。
           
            倒~,这样岂不是把A模块全部扔到核心模块里了?
           
      好,那修改一下,针对接口编程。
      把它们全部抽象成接口:
    [code:1]  interface IHelloSerivce
      {
            public IHelloObj sayHello(IHelloParam1 p1,IHelloParam2 p2);
      }[/code:1]
           
      然后再把IHelloSerivce,IHelloObj,IHelloParam1,IHelloParam2扔到核心模块里。
      这样的话,凭空多出许多的不需要的接口。(我觉得,只有IHelloSerivce是必要的。比如P1 p2只是一个简单的struct)
      还要有一个地方来注册这个IHelloSerivce是由具体的哪个模块的哪个类来实现的。
      对外接口多了也很头痛。
      编程的便利性就失去了。
     
     
      怎么解决这些烦恼?
   
最后更新时间:2006-07-14
设计起点错误.
这样的系统应该是多系统的集成.各个系统通过Web Service(或者其他机制)松散耦合.这样就不存在需要你所谓classload机制的地方.

我想你所说的接口污染问题是无法避免的,结果就是使程序无法编译,或是Down掉.
   
0 请登录后投票
最后更新时间:2006-07-14
楼上的想说soa?

呵呵。看来你不理解我想要的。

那在一个服务器上的不同模块互相调用也通过ws?
你试没试过直接方法调用和ws调用之间的性能差距?
把一个pojo暴漏成ws有多少工作量?
就是用spring也要每个ws写一个xml吧?
跨模块调用,事务怎么保证?

ws本身是,1。分布式应用,2。不同语言调用的。
   
0 请登录后投票
最后更新时间:2006-07-14
搂主的想法感觉跟eclipse的plug-in及至有些类似,不晓得你参考过eclipse osgi没有。
   
0 请登录后投票
最后更新时间:2006-07-14
引用
呵呵。看来你不理解我想要的。

我不知道我是否了解.但我认为你所说的"较大的项目"如果需要将那末多模块的业务逻辑混合在一个核心模块中,总是有问题的.
如果我没有理解错误,你是试图将一堆异构系统容纳在同一个框架下,同一个进程中运行.但这总是要付出代价的.
松散耦合是一种风险较低的方案.否则不论你的设计有多么完善,你的问题首先是:你怎么知道这些系统都支持你的设计呢?
引用
那在一个服务器上的不同模块互相调用也通过ws?

是的,没什么不可以.
引用
你试没试过直接方法调用和ws调用之间的性能差距?

我了解这个问题.问题是如果你的系统需要太多这样的东西,是不是说明设计出了问题呢?我的理解是可能是你的期望出了问题.
引用
跨模块调用,事务怎么保证?

这不是关键问题.问题还是你的设计怎么降低这种调用的次数.
   
0 请登录后投票
最后更新时间:2006-07-14
这个问题提得很有深度,也很实际,似乎也只有Classloader方案比较好解决了,不过多个应用互相调用的事务一致性有点麻烦:如果某操作中A应用调用B应用的功能,之间A,B应用任意一个数据库操作失败,那么整个事务就算是失败的.而Spring在这个情形下要解决,只能是同时修改多个版本的代码才能使用同一个TransactionContext, 但是这样一来就违背了当初不互相影响的要求了.或者可以不修改代码,每个子ClassLoader首选其它子ClassLoader的类,但是这样一来所有不同版本的Spring就必须保证完全兼容的了,这个似乎不太可能..
引用
独立性还包括这样的需求。各个模块引用的第三方项目互不干扰。

除了这点,其它都好解决.
   
0 请登录后投票
最后更新时间:2006-07-14
经过试验,想明白一些概念模糊的地方,基本能解决这些问题。
等我设计好了把文档与大家共享。
   
0 请登录后投票
最后更新时间:2006-07-18
我觉得core classloader和这些extension module之间不应该是父子关系。

所有的classloader, 包括core和extension module的class loader可以都是系统classloader的儿子。

可以做一个ClassLoaderManager,它负责管理core以及所有module的依赖关系。也就是说,ClassLoaderManager里面包含core和extension。(可以用弱引用,保证垃圾回收)

每个classloader都包含一个对ClassLoaderManager的引用(叫它global)。
查找类的时候,缺省从this找(这步就包括了标准的java classloader的代理模型),如果找不到,那么就交给global去找。

global负责先从core里面找,如果没有,找所有不是当前module的其它module。(如果当前是core,就直接返回,保证core的独立性)

大概应该就可以了。这个模型不同于标准的父子代理关系,它更象一个姐妹代理关系。
   
0 请登录后投票
最后更新时间:2006-07-18
agree!

我后来想好的模型就是ajoo所描述的。
:)
正在实现ing
   
0 请登录后投票
最后更新时间:2006-08-03
不知做的怎么样了?

我倒是刚写了一个。
发现很难对任意的ClassLoader对象作这种横向组合——sun的class loader的结构不好,对组合不友好。(一个classloader load出来的class,它再load别的class的时候,必然只能从那个classloader走,这样那个组合了所有姐妹classloader的超级classloader就用不到了。)

不过,我写了一个可以对一个目录树里面的所有jar文件进行树形管理的ClassLoader。

同一个目录里面的jar文件会优先于其它目录里面的jar文件。这样,可以按照模块分目录,把jar文件组织起来应该就可以了。这个实现还支持hot-swap。

如果需要,我可以贴出来。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐