领先一步
VMware 提供培训和认证,助您加速进步。
了解更多上个月,在最初的 4.0 版本发布近 4 年后,OSGi 联盟正式批准了 OSGi 服务平台 4.2 版本。公告的标题突出了 Blueprint Container 服务,这是 Compendium 规范的新增内容,基于 Spring Dynamic Modules(也称为 Spring OSGi)项目推广的编程模型。为了快速总结 Blueprint,我将直接引用 OSGi 规范中的一段话:
(Blueprint Container)[...] 定义了一个依赖注入框架,专用于 OSGi bundle,它理解服务的独特动态性。它提供了一种 OSGi bundle 编程模型,该模型具有最少的实现依赖性,并且 Java 代码中几乎没有意外的复杂性。
熟悉 IoC 概念或 Spring 及 Spring DM 配置的用户会发现 Blueprint 规范易于理解。事实上,由于它派生自 Spring DM,许多 Blueprint 概念、语法和术语都是相同的,在大多数情况下,在两者之间移植现有应用程序只需调整配置文件即可。在功能方面,Blueprint 提供了一个控制反转容器,支持构造函数注入和 Setter 注入、工厂方法、生命周期管理和回调、签名消歧以及类型转换等功能。在 OSGi 方面,可以使用导出器(exporters)和导入器(importers)来透明地发布和消费 OSGi 服务。
下面是一个 Blueprint 配置的代码片段,它创建了几个对象,导入了一个服务,将它们连接在一起,然后将目标作为 OSGi 服务暴露出来:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" default-activation="lazy">
<!-- basic object creation -->
<bean id="object" class="java.lang.Object"/>
<bean id="length" class="java.lang.Integer">
<argument value="4"/>
</bean>
<bean id="buffer" class="java.lang.StringBuffer" depends-on="simple">
<property name="length" ref="length"/>
</bean>
<bean id="current-time" class="java.lang.System" factory-method="currentTimeMillis" scope="prototype"/>
<bean id="list" class="java.util.ArrayList" destroy-method="clear" activation="eager">
<argument ref="length"/>
</bean>
<!-- service import -->
<reference id="ds" class="javax.sql.DataSource" filter="(batch-size=200)"/>
<bean id="consumer" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<property name="dataSource" ref="ds"/>
</bean>
<!-- service export -->
<service id="publisher" ref="consumer" auto-detect="interfaces"/>
</blueprint>
除了配置之外,Blueprint 还提供了一个小型的 API(通过 container 和 reflect 包)用于依赖查找、读取元数据或执行自定义类型转换,这在一定程度上类似于 Spring。有关 Blueprint 和 Spring DM 之间相似性(和差异性)的更多信息,请参阅 DM 2.0 M1 参考文档中的专门章节。
值得指出的是,尽管 Blueprint 依赖于 OSGi 4.2 API,但 Spring DM 2.x 不依赖。运行 OSGi 4.0 和 4.1 的用户可以安全地使用 Spring DM 2.x;只有 Blueprint 功能会被禁用,其余功能仍然可用。
使用 Spring DM 的主要优势之一是,可以从 OSGi 透明地完全访问 Spring 容器:无论您打算使用 Blueprint、Spring/Spring DM API 和配置,Spring DM 2.x 都可以在同一个应用程序中同时支持这两种风格,从而提供更大的灵活性。例如,就像在传统的 Spring 应用程序中一样,可以轻松地向 Blueprint bundle 添加字段注入或基于注解的配置,从而补充 Blueprint 的功能。
为了说明这一点,让我们来看一个规范示例,并将 Blueprint 配置与 JSR-250(Common Annotations)以及 Spring 3 中的一些新增功能(例如 JSR-330(Java 依赖注入)支持)结合起来。
public interface Echo {
public String echo(String m);
}
public class EchoImpl implements Echo {
String message;
public void setMessage(String m) {
this.message= m;
}
public String echo(String s) { return message + s; }
}
<blueprint>
<service id="echoService" interface="com.acme.Echo" ref="echo"/>
<bean id="echo" class="com.acme.EchoImpl"
<property name="message" value="Echo: "/>
</bean>
</blueprint>
我将在这个示例中使用 Maven,并遵循其项目布局约定:[caption id="attachment_2939" align="aligncenter" width="326"][/caption]
public class EchoImpl implements Echo {
@Inject
private PackageAdmin pkgAdmin;
String message;
public void setMessage(String m) {
this.message = m;
}
public String echo(String s) {
return message + s;
}
@PostConstruct
void startup() {
Bundle bnd = pkgAdmin.getBundle(getClass());
ExportedPackage pkg = pkgAdmin.getExportedPackage(Echo.class.getPackage().getName());
System.out.printf("Echo service bundle [%s] wired to bundles %s\n", bnd.getSymbolicName(),
Arrays.toString(pkg.getImportingBundles()));
}
}
<blueprint>
<service id="echoService" interface="com.acme.Echo" ref="echo" />
<bean id="echo" class="com.acme.internal.EchoImpl">
<property name="message" value="Echo: "/>
</bean>
<reference id="pkgAdmin"
interface="org.osgi.service.packageadmin.PackageAdmin" />
<context:annotation-config/>
</blueprint>
Excluded-Exports: *.internal*
注意,模板不包含关于注解或配置的任何信息——自 1.0.0.M6 版本以来,Bundlor 能够理解 Blueprint bundle,它会自动拾取并解析任何相关的配置和类。
# mvn package
大功告成。现在让我们运行示例。
Manifest-Version: 1.0
Export-Package: com.acme;version="0.0.0"
Bundle-Name: blueprint-atinject
Bundle-ManifestVersion: 2
Bundle-SymbolicName: blueprint-atinject
Import-Package: javax.annotation,javax.inject,org.osgi.framework,org.o
sgi.service.packageadmin
只需将生成的 jar 部署到 OSGi 4.2 框架中,同时部署 Spring DM 2.0.0.M1,您应该会看到以下输出:
INFO: Blueprint API detected; enabling Blueprint Container functionality
...
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
...
Echo service bundle [blueprint-atinject] wired to bundles []
...
INFO: Publishing service under classes [{com.acme.Echo}]
下面是我的 OSGi bundle 列表(通过调用ss命令在 equinox 中生成)。
0 ACTIVE org.eclipse.osgi_3.5.0.v20090520
1 ACTIVE com.springsource.slf4j.api_1.5.6
Fragments=2
2 RESOLVED com.springsource.slf4j.juli_1.5.6
Master=1
3 ACTIVE com.springsource.slf4j.org.apache.commons.logging_1.5.6
4 ACTIVE com.springsource.org.aopalliance_1.0.0
5 ACTIVE com.springsource.net.sf.cglib_2.1.3
6 ACTIVE org.springframework.asm_3.0.0.RC1
7 ACTIVE org.springframework.expression_3.0.0.RC1
8 ACTIVE org.springframework.core_3.0.0.RC1
9 ACTIVE org.springframework.beans_3.0.0.RC1
10 ACTIVE org.springframework.aop_3.0.0.RC1
11 ACTIVE org.springframework.context_3.0.0.RC1
12 ACTIVE org.springframework.osgi.io_2.0.0.M1
13 ACTIVE org.springframework.osgi.core_2.0.0.M1
14 ACTIVE org.springframework.osgi.extender_2.0.0.M1
15 ACTIVE com.springsource.javax.inject_0.9.0.PFD
16 ACTIVE com.springsource.javax.annotation_1.0.0
17 ACTIVE blueprint-atinject_0.0.0
您可以在此处找到项目档案(包含说明)。
通过在 OSGi 平台内采用事实标准(例如依赖注入),我们相信 Blueprint 对 OSGi 和非 OSGi 开发人员都有益,因为它鼓励 API 解耦和基础设施关注点的外部化,显著降低了创建和配置 OSGi 应用程序的入门门槛。
我们对未来的发展和当前正在开发的功能感到非常兴奋!
要获取有关 OSGi 和 Spring DM 的更多更新(和反馈!),请关注我们的博客和 Twitter(通过标签 #osgi、#springdm、#dmserver。本人在 @costinl 可用)。