一个成功的OSGi应用应该具备模块化、动态性、即插即用的特征,要做到这三点必须遵循以下原则:
一、接口与实现分离为不同Bundle
我们定义了一些接口放到独立的A Bundle里面,然后(比如)有两种A中接口的相关实现 分别放到B Bundle、C Bundle中。这样我们就可以方便的对同一种服务(A中接口的服务)自由 的选择不同服务。要引用其他Bundle的服务通过接口来引用。在Export-Packge ,Import- Package中尽量保证都是都是接口所在包,而具体的实现则在实现Bundle里面通过服务的形式发布 出去。这样我们就能动态的更换或更新服务了,同时我们能够很容易地在新Bundle中增加新的接 口实现,提高了系统的可扩展性。
二、面向接口编程
当一些接口(契约)在一个独立的Bundle中定义好以后,我们就可以在实现接口的 Bundle中去编写我们的具体应用,如果我们需要引用其他Bundle服务直接拿接口(契约) 去引用,如果我们想发布已经实现好的服务,可以用接口(契约)发布出去。总之,模 块之间的用接口(契约)去解耦,避免在实现代码中出现其他实现类的影子,必要是采用IoC
的编程方式或者采用工厂模式。这个原则也是在非OSGi编程中就应该遵循的。
三、面向切面编程
如果我们遇到这种情况,在程序代码中的有些操作是可选的,就是说在做一些逻辑处理之前 或之后要做一些可选的操作,比如事务处理。要做对处理前开始事务,处理完后提交事务,发生 异常回滚事务(这三中情况我们分别叫做前拦截、后拦截、异常拦截,拦截到的都是些代码逻辑 的切面,所以我们叫他面向切面编程(Spring里有个简称AOP)。除了这三种拦截,还有环绕 截。这个原则也是在非OSGi编程中就应该遵循的。
四、保持系统的动态性(即插即用,即删既无)
主要体现在两个方面:
1、系统的动态性体现在系统不会因为某些Bundle的卸载或不可用导致系统的崩溃性错误或无 意义的系统操作入口。
2、有新的Bundle安装时,相应的功能入口或挂接应自动完成。
具体的做法:
1、不强依赖其他Bundle的资源
不在Bundle中直接使用其他Bundle的资源,保证当被应用资源所在的Bundle卸载或 不可用时,不会发生系统崩溃或本Bundle不可用。比如在OSGi-Hibernate应用中,一个初始 化SessionFactory的Bundle需要加载其他Bundle声明的PO Class,最直接的办法就是把po所 在的包Import进来,但这是不提倡做的,如果所依赖的某个po的Bundle被卸载,这个初始化 SessionFacotry的Bundle就不能起来,而这个Bundle是系统基本Bundle,从而导致系统崩 溃。解决方法是,在初始化SessionFactory的Bundle中加上DynamicImport-Package: *,并 且po Class的注册应该跟po放到一个Bundle内,这样就保证了该Bundle需要PO的类时,采取 加载相关的Bundle中的Package。
2、不强依赖任何OSGi服务
在动态性系统里面,我们不能将对服务的依赖变成静态的行为,比如要引用一个服务,我 们必须考虑三种情况(1)服务不可用(2)服务可用,但不止一个。服务不可用时,我 们必须保证系统的正常运行,可以做一些处理,不如判断为空时的处理,或是在服务引用的 配置里加上cardinality="0..1"或cardinality="0..n"这样的配置。对于第二种情况,我们 可以利用OSGi的服务过滤的方式来从多个服务里选择我们需要的服务。如果默写服务对系统 的运行是至关重要的,我们就要强行去引用了,比如配置cardinality="1..1"。
3、监听系统动态变化
在动态性系统里,我们要自动监听系统的变化,做出相应的处理。具体实现时可采用OSGi 提供的各种监听器、Event Service、CM(Configuration Admin Service)、以及DS (Daclerative Service)的bind、unbind。SpringDM配置中的osgi:listener,或是引入JMX 的管理。
五、最小化依赖
目的是尽量减少Bundle之间的依赖,避免出现安装一个Bundle时,要安装N多其依赖的 Bundle的现象。具体做法:
1、使用Import-Package代替Required-Bundle
在实践中会发现用Required-Bundle最容易引起循环依赖,导致系统不能运行。除非要引 用其他Bundle提供的资源文件时会用到Required-Bundle,其他情况下尽量少用。
2、使用版本范围控制
在Import-Package中尽量指定应用版本,以减少OSGi容器运行时过多的判断。
3、设计Bundle时,要遵循低耦合、高内聚的原则,不要把Bundle不相关的功能放到Bundle 中。
六、避免依赖启动顺序
启动顺序依赖是指在系统中Bundle的启动会依赖其他Bundle的启动。也就是说被依赖的 Bundle为启动时,该Bundle启动不了,或一些服务引用不到。而且系统启动顺序依赖会造成启动 时间过长,因为这意味着要在启动的时候做很多工作。
在动态性系统中,任何Bundle的启动都不应该对别的Bundle造成强依赖。避免启动顺序依赖, 要做到一下几点:
1、不要在初始化Bundle时应用OSGi服务。
这一点要强调,如果在Bundle中使用了启动器(BundleActivator),避免在start方 法中做太多处理。因为启动器里面的start方法是该Bundle启动是第一个要执行的方法, (stop方法是Bundle停止时最后一个执行的方法),如果在start中做太多处理,会严重影响 系统的启动时间,而且这种做法破坏了系统的动态性。
2、使用ServiceTracker去动态获取所需要的OSGi服务。
3、使用DS或SpringDM动态获取OSGi服务。
OSGi开发原则
最新推荐文章于 2021-02-13 10:37:30 发布