来源: http://zcxblog.blogchina.com/blog/535738.html
今天在完成一个功能的时候,使用了ServiceLocate模式,
通过这个模式,在程序中可以自由的加载其他成员实现的功能模块
具体的做法:
1)定义标准的服务接口。
2)定义描述实现服务接口的xml文件。
3)程序读取该xml文件,使用Class.newInstance()实例化具体的服务对象。
4)建立一个特定服务和特定服务实现的对应的HashMap对象。完成注册任务。
5)主程序中根据具体的服务从HashMap中取得具体的对象进行服务。
通过这个模式,在程序中可以自由的加载其他成员实现的功能模块
具体的做法:
1)定义标准的服务接口。
2)定义描述实现服务接口的 xml文件。
3)程序读取该 xml文件,使用 Class.newInstance()实例化具体的服务对象。
4)建立一个特定服务和特定服务实现的对应的 HashMap对象。完成注册任务。
5)主程序中根据具体的服务从 HashMap中取得具体的对象进行服务。
这个方法还不错,可以完成基于 Interface的开发要求,利于 Test和程序的拓展性。
有新的要求出现后,只需要添加 xml中的元素和具体的实现类就可以了。
接下来,继续想。又发现了一些问题:
1) xml是和程序一起发布的,如果用户随意改动了。很明显程序会崩溃。
解决方法: xml放在 jar包中,使用 getClass().getResourceAsStream(String name)
自己加载进来。用户完全不知道具体的情况。
2)如果把 xml放在了 jar包中"藏起来",实际上原来带来的动态扩展的特性,
也就没有那么明显了。如何解决呢
细细想来,这个问题的关键在于,所有的服务实例对象的创建和注册都是在
主控程序中通过 xml来完成的。如果可以把这个注册和实例化的过程从主控程序
中分离出来,通过每个服务实例对象自动注册来完成,那么才算是真正的可拓展的。
如果需要完成新的功能,只需要把新的服务对象 Class发布,重新运行主控程序就会实现新的功能。(看起来就和 Eclipse一样)
这真是一个不错的想法,但是怎么做呢?
看看Eclipse如何做的。
http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html
首先要有一个规定的plugin deploy目录,这样主程序才知道从哪里加载。
要有一个plugin.xml文件描述这个plugin.这着文件中有属性:class="foo.bar.Plugin">
看上去和我们原来做的方式一样啊。但是它是如何把这个目录下的plugin都加载的呢?
(我没有看过 Eclipse的源码,不知道他是怎么写的)再想想,其实主要要解决的问题是不通过主框架程序注册服务实现,
应该由服务程序自己注册上来。按照这个思路,我想有两种解决方案。
1)服务接口添加registerService 方法。
* 在jar的METATINFO文件中定义类名。
* 从特定的目录中读取jar/class文件。
* 通过URLClassLoader.newInstance()加载
* 加载后把ServiceLoader作为参数出入 service.registerSevice()中
* service对象完成自己的注册。2)服务添加 static代码端在类被实例化的时候自动完成注册。
* 加载之前和上一个方法一样。
* 对 SeviceLoader对象实现为单态的模式。提供静态的注册方法。
* 在 servie对象中实现如下的代码段完成自动注册。
static
{
ServiceLoader.registerService(new service());
}
这样看来总算 OK了吧。