osgi 学习笔记一

来源:互联网 发布:java简历个人评价 编辑:程序博客网 时间:2024/05/21 10:25

浅析OSGI的bundle依赖


Bundle是OSGI中的基础元件,不同的bundle之间可以相互依赖、引用,这样许多bundle才会共同协作,实现一些比较复杂的功能。Bundle的依赖一直是一个比较棘手的问题,包括Lazy start等,下面我们具体Bundle依赖到底是怎么一回事。

测试场景:Eclipse 3.6, Equinox 

先看看基础的依赖问题

准备环境

新建2个插件,注意选择“An OSGI Framework”

 

新建2个基础plugin project:org.salever.osgi.depends.clientbundle、org.salever.osgi.depends.hostbundle

然后启动一个OSGI Framework,在Eclipse里面Run configuration里面,新建一个OSGI Framework:

在新建的OSGI Framework里面,仅选择新建的2个插件,然后点击add Required Bundles:

为了测试顺利,建议添加-clean参数:

如果不出意外,将会出现OSGI的控制台:

输入ss,将列举当前的bundles:

1
2
3
4
5
6
7
8
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  ACTIVE      org.salever.osgi.depends.hostbundle_1.0.0.qualifier
2  ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifier

这时候仅仅有三个bundle启动,下面我们将尝试添加依赖关系,然后看看依赖关系不满足的时候,bundle的表现。

依赖

我们将尝试几种不同的场景:

  1. 【LAZY下】依赖不满足的时候,bundle的行为
  2. 正常运行的bundle,强行停止其依赖的bundles,该bundle的行为
  3. 无依赖的情况下,bundle的行为

在测试之前,必须先把OSGI Framework配置改下,将所有的bundle该为Lazy start,不然影响测试结果。

注意红线部分的设置。然后重启OSGI Framework。出现以下的内容,表明此时所有的bundle都是Lazy-start并且没有启动:

1
2
3
4
5
6
7
8
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
3  <<LAZY>>    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
4  <<LAZY>>    org.salever.osgi.depends.clientbundle_1.0.0.qualifier

注意先要把Bundle都设为Lazy-start。实现Lazy-start的bundle很简单,在MANIFEST.MF中,添加

1
Bundle-ActivationPolicy: lazy

就可以了。

测试场景1——简单依赖

这时候修改新建的2个bundle,在org.salever.osgi.depends.clientbundle中添加对org.salever.osgi.depends.hostbundle的依赖:

保存重启OSGI Framework,然后尝试启动org.salever.osgi.depends.clientbundle

1
2
3
4
5
6
7
8
9
10
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
3  <<LAZY>>    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
5  <<LAZY>>    org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi> start 5

然后看看运行效果:

1
2
3
4
5
6
7
8
9
10
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
3  <<LAZY>>    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
5  ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi>

这时候org.salever.osgi.depends.clientbundle已经启动,而依赖的bundle——org.salever.osgi.depends.hostbundle依然是

1
3  <<LAZY>>    org.salever.osgi.depends.hostbundle_1.0.0.qualifier

看看clientbundle的header信息:

1
2
3
4
5
6
7
8
9
10
11
12
osgi> headers 5
Bundle headers:
 Bundle-ActivationPolicy = lazy
 Bundle-Activator = org.salever.osgi.depends.clientbundle.Activator
 Bundle-ManifestVersion = 2
 Bundle-Name = Clientbundle
 Bundle-RequiredExecutionEnvironment = JavaSE-1.6
 Bundle-SymbolicName = org.salever.osgi.depends.clientbundle;singleton:=true
 Bundle-Version = 1.0.0.qualifier
 Import-Package = org.osgi.framework;version="1.3.0"
 Manifest-Version = 1.0
 Require-Bundle = org.salever.osgi.depends.hostbundle;bundle-version="1.0.0"

这时候尝试停止hostbundle:

1
2
3
4
5
6
7
8
9
10
osgi> stop 3
 
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
3  RESOLVED    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
5  ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifier

说明了即使被依赖的bundle不启动,clientbundle亦一样可以启动。

这里的依赖仅仅是简单的Add Required Bundle,没有使用里面的具体类,如果使用了依赖的bundle中的类了么?

测试场景2——添加具体Class调用

在hostbundle中新建类HostService:

1
2
3
4
5
6
7
8
9
10
11
12
13
packageorg.salever.osgi.depends.hostbundle;
 
/**
 * @author LiXP
 *
 */
publicclass HostService {
 
    publicstatic void service() {
        System.out.println(HostService.class.toString() + ": Service");
    }
 
}

然后Export这个package,使其能被其他bundle使用:

1
Export-Package: org.salever.osgi.depends.hostbundle

最后在clientbundle中添加使用,修改ClientActivator.java,使其在启动的时候调用

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * (non-Javadoc)
 *
 * @see
 * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
 * )
 */
publicvoid start(BundleContext bundleContext) throwsException {
    ClientActivator.context = bundleContext;
 
    HostService.service();
 
}

重启OSGI Framework,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  <<LAZY>>    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
2  <<LAZY>>    org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi> start 2
classorg.salever.osgi.depends.hostbundle.HostService: Service
 
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  ACTIVE      org.salever.osgi.depends.hostbundle_1.0.0.qualifier
2  ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi>

这时候,hostbundle也启动了。这个与OSGI的lazy-start机制有关。bundle的lclass或者其它资源被Class loader装载的时候,该bundle才会启动。注意<<LAZY>>和RESOLVED 是2种状态。

 

测试场景3——强制停止依赖的插件

停止hostbundle:

1
2
3
4
5
6
7
8
9
10
11
12
osgi> stop 1
 
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  RESOLVED    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
2  ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi>

clientbundle依然运行,说明在bundle已经启动以后,停止依赖的bundle,对其无影响。

依次停止2个bundle,然后启动clientbundle,看看结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
osgi> stop 2
 
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  RESOLVED    org.salever.osgi.depends.hostbundle_1.0.0.qualifier
2  RESOLVED    org.salever.osgi.depends.clientbundle_1.0.0.qualifier
 
osgi> start 2
classorg.salever.osgi.depends.hostbundle.HostService: Service
 
osgi>

2个bundle都启动。

修改一下代码,看看如果clientbundle一直调用hostbundle的时候,bundle的行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * (non-Javadoc)
 *
 * @see
 * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
 * )
 */
publicvoid start(BundleContext bundleContext) throwsException {
    ClientActivator.context = bundleContext;
 
    newThread(newRunnable() {
        @Override
        publicvoid run() {
            while(true) {
                HostService.service();
                try{
                    Thread.sleep(5000);
                }catch(InterruptedException e) {
                }
                System.out.println(this.toString() + ": Sleep 5000ms");
            }
 
        }
    }).start();
 
}

这里每隔5s,会发生一次调用:

1
2
3
4
osgi> org.salever.osgi.depends.clientbundle.ClientActivator$1@1808199: Sleep 5000ms
classorg.salever.osgi.depends.hostbundle.HostService: Service
org.salever.osgi.depends.clientbundle.ClientActivator$1@1808199: Sleep 5000ms
classorg.salever.osgi.depends.hostbundle.HostService: Service

然后停止hostbundle:

ssFramework is launched.idState       Bundle0ACTIVE      org.eclipse.osgi_3.6.2.R36x_v201102101RESOLVED    org.salever.osgi.depends.hostbundle_1.0.0.qualifier2ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifierosgi> org.salever.osgi.depends.clientbundle.ClientActivator$1@1808199: Sleep 5000msclass org.salever.osgi.depends.hostbundle.HostService: Service

试试卸载hostbundle:

osgi> uninstall 1osgi> ssFramework is launched.idState       Bundle0ACTIVE      org.eclipse.osgi_3.6.2.R36x_v201102102ACTIVE      org.salever.osgi.depends.clientbundle_1.0.0.qualifierosgi> org.salever.osgi.depends.clientbundle.ClientActivator$1@763f5d: Sleep 5000msclass org.salever.osgi.depends.hostbundle.HostService: Serviceorg.salever.osgi.depends.clientbundle.ClientActivator$1@763f5d: Sleep 5000msclass org.salever.osgi.depends.hostbundle.HostService: Serviceorg.salever.osgi.depends.clientbundle.ClientActivator$1@763f5d: Sleep 5000msclass org.salever.osgi.depends.hostbundle.HostService: Service

说明,只要bundle启动了,就算依赖的bundle没有了,它也不会受其影响。一个可能的解释为,OSGI Framework缓存了这些bundle资源。

测试场景3——依赖的插件不存在

最后我们看看,依赖的bundle不存在的时候,bundle的行为。

回到New OSGI Framework的页面,去掉org.salever.osgi.depends.hostbundle。

启动环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
osgi> !SESSION 2012-04-0517:22:06.432-----------------------------------------------
eclipse.buildId=unknown
java.version=1.6.0_17
java.vendor=Sun Microsystems Inc.
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
Command-line arguments:  -dev file:E:/workspace/common_ws/.metadata/.plugins/org.eclipse.pde.core/New OSGI/dev.properties -os win32 -ws win32 -arch x86 -consoleLog -console -clean
 
!ENTRY org.eclipse.osgi 20 2012-04-0517:22:07.308
!MESSAGE One or more bundles are not resolved because the following root constraints are not resolved:
!SUBENTRY1org.eclipse.osgi 20 2012-04-0517:22:07.309
!MESSAGE Bundle initial@reference:file:E:/workspace/common_ws/org.salever.osgi.depends.clientbundle/ was not resolved.
!SUBENTRY2org.salever.osgi.depends.clientbundle 20 2012-04-0517:22:07.309
!MESSAGE Missing required bundle org.salever.osgi.depends.hostbundle_1.0.0.
 
!ENTRY org.eclipse.osgi 20 2012-04-0517:22:07.311
!MESSAGE The following is a complete list of bundles which are not resolved, see the prior log entryforthe root cause ifit exists:
!SUBENTRY1org.eclipse.osgi 20 2012-04-0517:22:07.311
!MESSAGE Bundle org.salever.osgi.depends.clientbundle_1.0.0.qualifier [1] was not resolved.
!SUBENTRY2org.salever.osgi.depends.clientbundle 20 2012-04-0517:22:07.312
!MESSAGE Missing required bundle org.salever.osgi.depends.hostbundle_1.0.0.

出现错误信息,尝试列举已有的bundle:

1
2
3
4
5
6
7
osgi> ss
 
Framework is launched.
 
id  State       Bundle
0  ACTIVE      org.eclipse.osgi_3.6.2.R36x_v20110210
1  INSTALLED   org.salever.osgi.depends.clientbundle_1.0.0.qualifier

bundle状态为已安装,而没有启动,尝试启动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
osgi> start 1
org.osgi.framework.BundleException: The bundle "org.salever.osgi.depends.clientbundle_1.0.0.qualifier [1]" could not be resolved. Reason: Missing Constraint: Require-Bundle: org.salever.osgi.depends.hostbundle; bundle-version="1.0.0"
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolverError(AbstractBundle.java:1317)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolutionFailureException(AbstractBundle.java:1301)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:319)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:284)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:276)
    at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:252)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:155)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:156)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.runConsole(FrameworkConsole.java:141)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:105)
    at java.lang.Thread.run(Thread.java:619)

这里就很好的解释了,为什么我们再运行Eclipse RCP插件时候,出现的一些类似错误的原因了。

 总结

  1. 一般情况下,最好把bundle设为Lazy-start,这样可以节约资源,在必要的情况下,bundle会自动启用
  2. 如果依赖的bundle停止了,正在运行的bundle不会马上停止,仍然会继续运行
原创粉丝点击