1.前言
本章内容接第二篇 玩转OSGI-ApacheFelix(二)IDEA,注意介绍如何使用maven插件进行项目打包配置,后面内容可能会进行更新,根据目前掌握资料进行第一步记录汇总。
2.maven插件介绍
你可能会用到以下插件来实现你的需求,但是最重要的莫过于maven-bundle-plugin,这个插件用于OSGI配置打包,生成manifest文件,也就是配置元数据,进行打包配置描述,其他插件在java开发中应该或多或少都接触过,本章内容主要对maven-bundle-plugin进行说明
- maven-dependency-plugin
- maven-jar-plugin
- maven-bundle-plugin
- maven-assembly-plugin
- spring-boot-maven-plugin
3.maven-bundle-plugin
接第二章内容中的felix-client内容,给出一个示例pom配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>felix-demo</artifactId> <groupId>com.nxhz.felix</groupId> <version>1.0.4</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>felix-client</artifactId> <dependencies> <dependency> <groupId>com.nxhz.felix</groupId> <artifactId>felix-server</artifactId> <scope>provided</scope> </dependency> </dependencies> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> </execution> </executions> <configuration> <outputDirectory>${project.build.directory}/libs/</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> <excludes>**/*.zip</excludes> <includes>**/*.jar</includes> <includeScope>compile</includeScope> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.2</version> <configuration> <excludes>classes/*.properties</excludes> <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>3.5.0</version> <extensions>true</extensions> <executions> <execution> <id>bundle-manifest</id> <phase>process-classes</phase> <goals> <goal>manifest</goal> </goals> </execution> </executions> <configuration> <unpackBundle>false</unpackBundle> <supportedProjectTypes> <supportedProjectType>jar</supportedProjectType> <supportedProjectType>bundle</supportedProjectType> <supportedProjectType>war</supportedProjectType> </supportedProjectTypes> <instructions> <Bundle-Name>${project.artifactId}</Bundle-Name> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Bundle-ClassPath>.,classes,{maven-dependencies}</Bundle-ClassPath> <Bundle-Vendor>Morpheus</Bundle-Vendor> <Export-Package>!*</Export-Package> <Embed-Directory>libs</Embed-Directory> <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> <Embed-Transitive>true</Embed-Transitive> <!-- <Import-Library>org.springframework.spring;version="[5.0, 5.2.8.RELEASE)"</Import-Library>--> <Export-Package>com.nxhz.felix</Export-Package> <Import-Package> org.osgi.framework,com.nxhz.felix.server;version="${project.version}" </Import-Package> <Bundle-Activator> com.nxhz.felix.client.ClientBundleActivator </Bundle-Activator> <!-- <Web-ContextPath>/client</Web-ContextPath> <MaxDataStorageSize>104857600</MaxDataStorageSize>--> </instructions> </configuration> </plugin> </plugins> </build> </project>
可能你看到的大部分资料或者博客都给出一个简单示例,整个人都有点懵,这玩意我弄过去配置上,为啥不能用,这里可能最主要的影响是OSGI包开发规则,不论插件怎么用,需要你先系统学习一下OSGI规范,根据规范进行插件配置,说白了,这个插件是根据OSGI规范进行配置,生成你需要的manifest文件打包到jar包中。下面介绍一下我搜集到插件相关的参数配置说明。
3.1 参数说明
属性 | 属性描述 |
---|---|
Bundle-Activator | Bundle 的 Activator 类名 |
Bundle-Category | Bundle 的分类属性描述 |
Bundle-Classpath | Bundle 的 Classpath |
Bundle-Copyright | Bundle 的版权 |
Bundle-Description | Bundle 的描述信息 |
Bundle-DocURL | Bundle 的文档 URL 地址 |
Bundle-Localization | Bundle 的国际化文件 |
Bundle-ManifestVersion | 定义 Bundle 所遵循的规范的版本, OSGI R3 对应的值为1, OSGI R4 对应的值为2 |
Bundle-Name | Bundle的有意义的名称 |
Bundle-NativeCode | Bundle 所引用的 Native Code 的地址 |
bundle-RequiredExecutionEnvironment | Bundle 运行所需要的环境,如可指定为需要 OSGI R3、Java1.4、Java1.3 等 |
Bundle-SymbolicName | Bundle 的唯一标识名,可采用类似 java package 名的机制来保证唯一性 |
Bundle-Version | Bundle 的版本 |
Dynamiclmport-Package | Bundle 动态引用的 package |
Export-Package | Bundle对外暴露的 package |
Fragment-Host | Fragment 类型 Bundle 所属的 Bundle 名 |
Import-Package | Bundle 引用的 package |
Require-Bundle | Bundle 所需要引用的其他的 Bundle |
3.2 Bundle-SymbolicName
Bundle-SymbolicName(符号名称) 是唯一必须指定的。通过 bundle 的符号名称和版本号可以在框架中惟一的确定一个 bundle。也就是说,如果一个 bundle 和另外一个 bundle 有着同样的符号名称和版本号,那么这两个 bundle 就是等价的。
Bundle-Name 是给用户读的,而 Bundle-Symbolicname 是给 OSGi 框架读的,让 OSGi 框架能够唯一标识一个 bundle。
示例:
Bundle-SymbolicName: com.edu.osgi.hellowrod
3.3 Bundle-Version
格式:主版本号(Major) + 副版本号(Minor) + 微版本号(Micro) + 限定符串(Qualifier)
bundle-version: 1.0.0.bate1
- 默认值为:0.0.0
- 主版本号、副版本号、微版本号必须是数字
- 限定字符串可以为空,默认为空
- 版本号是可以进行比较的,比较是根据主版本号、小版本号、微版本号的顺序进行比较。最后是字符串的限定符比较。eg:1.0.0.2016213 > 1.0.0
3.4 Export-Package
标准的 jar 文件默认公开一切内容,而 bundles 默认不公开任何内容 OSGi 通过 Export-Package 公开内容
- 可以导出多个包,多个用逗号隔开
- 可以给导出包增加任何属性,以区分导出包
- 导出的包 version 默认为 0.0.0
Export-Package: com.edu.api Export-Package: com.edu.api;version="1.0.0" Export-Package: com.edu.api,com.edu.util;version="1.0.0"
- 当导出一个包的时候,默认导出该包的所有类、接口。可以设置过滤条件:include 包含;exclude 排除
Export-Package: com.edu.api;include:="*Service" Export-Package: com.edu.api;exclude:="*Impl"
3.5 Import-Package
OSGi 要求 bundle 显示声明对外部代码的依赖:
- 不能导入 java.*
- 导入一个包,不会导入它的子包
- 通过增加属性导入特定的包
Import-Package: com.edu.api Import-Package: com.edu.api;version="1.0.0"
- Import-Package 版本过滤:
语法 含义 [min,max) min<=x<max [min,max] min<=x<=max (min,max] min<x<=max (min,max) min<x<max min min<=x [1.0.0,1.0.0] 精确指定一个版本 Import-Package: com.edu.api;version="[1.0.0,2.0.0)" Import-Package: com.edu.api;version="1.0.0"
- Import-Package 属性过滤:
Import-Package: com.edu.api;type=”apache”
默认情况下 bundle2 虽然没有声明自定义属性 type,但在默认情况下这并不会产生匹配冲突。如果要改变这种情况,可以使用 mandatory 附加参数,强制要求必须存在扩展属性オ能成功匹配。
# bundle1 Import-Package: com.edu.api;type="1";mandatory:="type" # bundle2 Export-Package: com.edu.api Export-Package: com.edu.api;type="1"
注意: type 是属性;mandatory 是 OSGi 的指令,指令前必须加 “:”
- Import-Package 可选导入:
在大多数情况下,导入某个 Package,就说明当前这个 bundle 的正常运行是必须依赖导入的 Package 的。但还有另外一些场景导入某个 Package 是为了实现一些不影响 Bundle 正常运行的附加功能,比如 Apache thrift 里面会用到 httpclient。但是只是在特殊情況下才会用到,此时就不需要强行依赖 httpclient 了。
# resolution 可选值 mandatory(默认) 和 optional Import-Package: com.edu.api;resolution:="optional"
3.6 DynamicImport-Package
定义需要动态导入的包。这部分定义没有在 bundle 解析过程中使用,而是在运行时动态解析并加载共享包。
动态导入和可选导入实现的功能有些类似,它们的共同特征是在 bundle 解析期间即使找不到要导入的依赖,也不会导致解析失败。它们的区别是,动态导入每次加载包中的类都会尝试去查找动态导入包,而可选导入包只有在 bundle 解析时才进行连接尝试
DynamicImport-Package: *
DynamicImport-Package: com.edu.*;type=1
不推荐使用,尽量用 Import-Package。
3.7 Bundle-Classpath
Bundle-Classpath 标记有默认值 “.”,它代表该 bundle 的根目录,或者说代表该 Bundle 的 JAR 文件
- 可以设置多个,多个用逗号隔开
- 一旦定义了 Bundle-Classpath 就需要显示加入 “.”
- 按照声明的顺序搜索 bundle 类路径条目
Bundle-Classpath: .,lib/xxx.jar
一般用于非 bundle 包的引用,不推荐使用,违反了 bundle 的使用原则。