扩展模型指一个Bundle在扫描其他Bundle内容的过程中,该Bundle代表被扫描Bundle执行其Action. 而在SpringDM中,扩展模型指当在MANIFEST.MF文件或Bundle的内容中有指定的扩展存在时,SpringDM应该自动
的触发连锁的事件(Event),即创建Spring Context, 该Context包括一个特指的类型上下文:OsgiBundle-
XmlApplicationContext.
任何部署到OSGi环境中的Bundle,SpringDM将检查该Bundle的SpringDM触发点,如果找到该出发点,该
Bundle将被赋予一个OsgiBundleXmlApplicationContext 类型的上下文;如果没找到触发点,SpringDM日志
将输出日志:
No Application context created for bundle<bundle_name>
但是扫描仍将继续。
SpringDM中有两中类型的Extender: Stand Extender和Web Extend,用于创建Context的默认Trigger如下:
Stand Extender:
/METa-INF/spring/*.xml: 放置与搞目录下的xml配置文件将用于SpringContext的创建;
Spring-Context mainfest value:这是一种更细粒度度的控制SpringContext的创建;
Web Extender:
.war bundle extension: 以.war作为扩展名表明该Bundle将被部署一个Web应用。
The stand extender primarily listens for bundle starting events, but it also looks for Spring-powered bundles that are already in the active state when it is itself started.
The default extender behavior is to retrieve the Spring configuration files from the bundle space, as it’s defined in the OSGi specification.
1. 标准的SpringOSGi组件的结构
1.1 DEFAULT BEHAVIOR FOR LOCATING SPRING CONFIGURATION FILES
my-springpowered-bundle.jar
META-INF/
MANIFEST.MF
spring/
application-context-1.xml
application-context-2.xml
com/
manning/
sdmia/
...
1.2 DEFINING THE LOCATION OF SPRING CONFIGURATION FILES WITH THE SPRING-CONTEXT
HEADER
Spring-Context: config/app-context-1.xml, config/app-context-2.xml
Spring-Context: config/*.xml
Spring-Context: config/**/*.xml
如果一个Bundle中同时有上述两种配置方式存在,则第二种优于第一种;如果一个Bundle 有Fragement,则
Fragement中的配置优于Host Bundle中得配置。
1.3 SPRING DM’S RESOURCE LOCATION BEHAVIOR
Spring Resource Abstraction
The Spring Framework defines an abstraction to load resources from an application context. This
abstraction is based on the Resource interface, which represents the access to a resource and is
agnostic to the underlying resource medium (filesystem, classpath, URL, and so on). Spring
defines the ResourceLoader interface, which is meant to be implemented by objects that can load
resources (a Spring application context always implements this interface).
Spring supports several prefixes: classpath, file, http.
Spring DM introduces a new Resource implementation, OsgiBundleResource , which encapsulates
all the necessary logic for proper resource loading from a bundle in an OSGi environment.
OSGi resource search strategies with Spring DM:
(1)OSGi search strategy:Class space
Prefixes:classpath:,classpath*:
Description:Search is delegated to the bundle classloader. The bundle itself, imported packages,
and required bundles are then scanned using the same semantics as the Bundle.getResource
method.
(2)OSGi search strategy:JAR file
Prefixes:osgibundlejar:
Description:Only the bundle itself is scanned, using the same semantics as the Bundle.getEntry
method.
(3)OSGi search strategy:Bundle space
Prefixes:osgibundle:
Description:The bundle and its fragments (if any) are scanned. Delegates internally to the
Bundle.findEntries method. This is Spring DM’s default resource-loading strategy.
配置示例:
Spring-Context: config/application-context.xml
Spring-Context: osgibundle:config/application-context.xml
这两种配置在OSGi环境中是等价的。
<bean id="someBean" class="com.manning.sdmia.SomeBean">
<property name="resource" value="classpath:help/section1.html" />
</bean>
1.4 ORGANIZING SPRING CONFIGURATION FILES IN A BUNDLE
A typical Spring-powered bundle of this sort would have the following structure:
my-springpowered-bundle.jar
META-INF/
MANIFEST.MF
spring/
modulename-context.xml
modulename-osgi-context.xml
com/
manning/
sdmia/
...
2. Bundle中初始化和销毁Spring容器
When the Spring DM extender is started, it scans the OSGi container for bundles in the active
state and bootstraps the application contexts for those it identifies as Spring-powered.
The Spring DM extender creates application contexts asynchronously; application contexts are
started in a different thread than the one that started the bundle (usually a thread owned by the
OSGi platform).
SpringDM在不同的线程中创建上下文主要有以下两个原因:
(1)OSGi规范推荐Event尽力在短时间 内进行,而创建应用上下文是需要时间的,如果创建应用上下文发生在OSGi
Event线程中,它将会阻止平台中其他任务的运行从而减缓了容器的启动;
(2)创建一个应用上下文时,The Extend Bundle需要应用上下文中Service的依赖被满足;如果创建上下文这个
任务是同步执行的,那么Bundle启动的顺序就需要很仔细的管理,要避免Service之间循环依赖现象发生。
The Spring DM extender is a bundle listener!
In Spring DM 1.2, the extender is a synchronous bundle listener, registered by the activator of the
Spring DM extender bundle. What exactly is a synchronous bundle listener? It’s an
implementation of the observer pattern , which allows code to react to bundle events, such as
activation, startup, or stopping. There are two kinds of bundle listeners, synchronous and
asynchronous (represented by two interfaces, SynchronousBundleListener and BundleListener
respectively), and the way the OSGi platform notifies them is slightly different.
Synchronous listeners receive more events than their asynchronous brethren (兄弟), as they’re
notified of starting and stopping events (the targeted bundle is on the way to being started or
stopped, respectively). Second, they’re called during the processing of the event . In the case of
bundle startup, the caller asks the platform to start the bundle, the platform notifies the
synchronous listeners, each does its work, and the bundle is started (and then the platform
broadcasts a started event, but that’s another story). With the synchronous method, listeners are
always notified during the processing of the event.
Asynchronous bundle listener notification isn’t as straightforward as the synchronous case. The
OSGi platform doesn’t place any constraints on the timeliness of notification and can add events
to a queue and let a background thread dispatch them to the asynchronous listeners. There is no
guarantee that event ordering is respected (the started event of the bundle could be delivered
after the corresponding stopped event). This doesn’t make asynchronous listeners useless, but
the dispatch mechanism needs to be understood when writing listeners of this type!
The BundleListener and SynchronousBundleListener interfaces define the same method, the
synchronous flavor being simply a marker-based extension of the asynchronous interface.
Synchronous bundle listeners must be used with caution, because they can slow the whole
platform if their processing takes too much time. The Spring DM extender is a synchronous
bundle listener but it delegates the creation of Spring application contexts to different threads by
default.
3. HOW SPRING DM DESTROYS APPLICATION CONTEXTS
The Spring DM extender takes care of the destruction of application contexts (on stopping bundle
events ) and accomplishes this crucial operation in a managed and safe way.
Through application context destruction, Spring DM accomplishes the following things:
■ Calls the shutdown method on Spring beans
■ Unregisters exported services
■ Informs the OSGi container that imported services are no longer used
The destruction is handled synchronously : the OSGi container is told to stop a Spring-powered
bundle, it sends a stopping event, the Spring DM extender receives the event and stops the
bundle application context (in the same thread ), and then control returns to the container, which
then stops the bundle.
The destruction is done synchronously because the application context must be destroyed before
the bundle is stopped. Once stopped, a bundle—and in particular, its bundle context—can’t be
used anymore.
4. STOPPING THE EXTENDER
Stopping the extender consists of destroying the application contexts in the right order . Why must
there be a “right” order? Well, application contexts can have dependencies on each other; some
can export services that others consume. The right order is therefore based on the way bundles
are connected through the service registry. Spring DM must compute the dependency graph of
Spring-powered bundles by analyzing their service relationships.
解决依赖关系的SpringDM的算法:
Spring DM would first track bundles that either don’t export any services, or export services that
aren’t referenced (used). These bundles are destroyed immediately (although Spring DM will
additionally attempt to do this in the reverse order of their creation) and whatever services
they’re using are released. The services these bundles were using might then no longer be
referenced, and Spring DM would find their owning bundles and destroy their application contexts.
This cycle continues until there are no more application contexts left to shut down.
解决循环依赖关系:
In this case, Spring DM has no choice other than to break the cycle by trying to find the most
appropriate bundle to stop first. Spring DM bases its choice on an OSGi property of services: the
service ranking . Services are looked up from the service registry by their interface. In the case
that there are several services implementing the same interface, the one with the highest service
ranking is returned by the OSGi platform. For each remaining bundle, Spring DM finds the highest
service ranking number and destroys the application context whose bundle has the lowest service
ranking among the set just calculated. If there is a tie in lowest ranking, Spring DM uses the
bundle ID (an indicator of start order) as a tiebreaker, stopping the bundle with the highest ID
(which was thus started last). This will hopefully break the cycle, and Spring DM can restart its
algorithm at the beginning to find other application contexts to destroy.
5. Customizing application context creation
Directives for the Spring-Context header:
配置文件默认值:
Bundle-Context:*;
Spring-Context:*;
配置文件默认路径:
/META-INF/spring,如果指定了其他配置文件路径,默认路径将被忽略。
(1)Directive:create-asynchronously
Possible values:true, false
Description:Tells the extender to create the bundle application context asynchronously or
synchronously. Default is true (asynchronously).
(2)Directive:wait-for-dependencies
Possible values:true, false
Description:Controls whether application context creation should wait for all mandatory imported
services to be available. Default is true.
(3)Directive:timeout
Possible values:integer
Description:Indicates the time (in seconds) to wait for mandatory imported services to become
available before failing the creation of the application context. Default is 300 seconds (5 minutes).
(4)Directive:publish-context
Possible values:true, false
Description:Controls whether the bundle application context is published in the OSGi service
registry. Default is true.
5.1 CREATE-ASYNCHRONOUSLY
By setting the create-asynchronously directive to false, the creation of the application context
occurs in a thread managed by the OSGi platform,how to set the create-asynchronously
directive:
(1) 用默认的配置路径异步创建上下文(默认值):
Spring-Context: *;create-asynchronously:=true
(2) 指定配置文件路径同步创建上下文:
Spring-Context: config/application-context.xml;create-asynchronously:=false
5.2 WAIT-FOR-DEPENDENCIES
默认值:Spring-Context: *;wait-for-dependencies:=true
Spring-Context: config/application-context.xml;wait-for-dependencies:=false
With this setting, mandatory dependencies are treated as optional, and Spring beans using them
will be injected with a service proxy that isn’t currently backed by an actual service retrieved
from the service registry.
推荐异步创建,同步情况下有可能导致依赖死锁。
5.3 TIMEOUT
默认值:Spring-Context:*;timeout:=300
Spring-Context: config/application-context.xml;timeout:=120
With this setting, an application context will wait for its mandatory dependencies for 300 seconds
before the creation attempt fails. The timeout directive makes sense only when application
contexts wait for their mandatory dependencies, so it’s ignored when the wait-for-dependencies
directive is set to false。
5.4 PUBLISH-CONTEXT
默认值:Spring-Context:*;publish-context:=true
Spring-Context: config/application-context.xml;publish-context:=false
指从Bundle配置文件路径中创建上下文,但是不将该上下文作为一个服务注册至OSGi 注册中心。