基于Maven构建OSGI应用(Maven和OSGI结合)

基于Maven构建OSGI应用。

使用Maven来构建项目,包括项目的创建、子模块buldle的创建等。使用OSGI来实现动态模块化管理,实现模块的热插拔效果(即插即用)。

创建一个Maven项目:helloworld,并在该项目下创建两个Maven 子模块:helloworld-client、helloworld-server。

创建 helloworld maven项目、填写参数及Advanced Settings:

基于Maven构建OSGI应用(Maven和OSGI结合)_第1张图片

创建 helloworld-server maven子模块:

基于Maven构建OSGI应用(Maven和OSGI结合)_第2张图片

同样的方式再创建 helloworl-client maven 子模块。

接下来就是 hellworld-server、helloworld-client 编码以及OSGI及编译打包配置。

OSGI及编译打包配置,直接通过修改3个pom文件(1个主pom、2个子模块的pom)来配置,最终配置结果如下:

1)代码结构:

基于Maven构建OSGI应用(Maven和OSGI结合)_第3张图片

client->Activator.java:

package com.xxx.osgi.helloworld.client;

import com.xxx.osgi.helloworld.server.HelloWorldImpl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import java.util.Objects;

/**
 * @author frank
 * @date 2023/12/8
 */
public class Activator implements BundleActivator {
    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("helloworld-client: start");
        System.out.println("helloworld-client: call server getHelloMsg()");

        ServiceReference reference = bundleContext.getServiceReference(HelloWorldImpl.class);
        if (Objects.nonNull(reference)) {
            HelloWorldImpl service = bundleContext.getService(reference);
            if (Objects.nonNull(service)) {
                String msg = service.getHelloMsg("Frank");
                System.out.println("SUCCESS: return msg is:\n" + msg);
            } else {
                System.out.println("ERROR: service not found!");
            }
            bundleContext.ungetService(reference);
        } else {
            System.out.println("ERROR: service reference not found!");
        }
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("helloworld-client: stop");
    }
}

server->Activator.java

package com.xxx.osgi.helloworld.server;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Objects;

/**
 * @author frank
 * @date 2023/12/9
 */
public class Activator implements BundleActivator {
    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("helloworld-server: start");
        HelloWorldImpl server = new HelloWorldImpl();
        Dictionary properties = new Hashtable();
        bundleContext.registerService(HelloWorldImpl.class, server, properties);
        System.out.println("helloworld-server: 服务已发布(注册)!");
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("helloworld-server: stop");
    }
}

server->IHelloWorld.java

package com.xxx.osgi.helloworld.server;

/**
 * @author frank
 * @date 2023/12/9
 */
public interface IHelloWorld {
    String getHelloMsg(String name);
}

server->HelloWorldImpl.java

package com.xxx.osgi.helloworld.server;

/**
 * @author frank
 * @date 2023/12/9
 */
public class HelloWorldImpl implements IHelloWorld {
    public String getMethodName() {
        return "[" + Thread.currentThread().getStackTrace()[2].getMethodName() + ":" +
                Thread.currentThread().getStackTrace()[2].getLineNumber() + "] ";
    }

    public String getHelloMsg(String name) {
        return getMethodName() + " HelloWorld " + name;
    }
}

2)主pom:


  4.0.0

  org.xxx.osgi
  helloworld
  1.0.0-SNAPSHOT
  
    helloworld-client
    helloworld-server
  
  pom

  helloworld
  http://maven.apache.org

  
    UTF-8
    8
    2.4.0
  

  
    
      junit
      junit
      3.8.1
      test
    
    
      
      
      
      
      org.eclipse
      osgi
      3.10.0-v20140606-1445
      provided
    
  

3)hellworld-client 子模块pom:


    
        helloworld
        org.xxx.osgi
        1.0.0-SNAPSHOT
    
    4.0.0

    helloworld-client
    bundle

    helloworld-client
    http://maven.apache.org

    
        UTF-8
    

    
        
        
            org.xxx.osgi
            helloworld-server
            ${project.version}
        
    

    
        
            
                
                
                org.apache.felix
                maven-bundle-plugin
                ${parent.maven.bundle.plugin.version}
                true
                
                    
                        
                        
                        ${project.name}
                        $(replace;${project.artifactId};-;_)
                        ${project.version}
                        com.xxx.osgi.helloworld.client.Activator
                        org.osgi.framework,com.xxx.osgi.helloworld.server;version=${project.version}"
                        
                            com.xxx.osgi.helloworld.client;version="${project.version}"
                        
                    
                
            
        
    

4)helloworld-server 子模块pom:


    
        helloworld
        org.xxx.osgi
        1.0.0-SNAPSHOT
    
    4.0.0

    helloworld-server
    bundle

    helloworld-server
    http://maven.apache.org

    
        UTF-8
    

    
        
    

    
        
            
                
                
                org.apache.felix
                maven-bundle-plugin
                ${parent.maven.bundle.plugin.version}
                true
                
                    
                        
                        
                        ${project.name}
                        $(replace;${project.artifactId};-;_)
                        ${project.version}
                        com.xxx.osgi.helloworld.server.Activator
                        org.osgi.framework
                        
                            com.xxx.osgi.helloworld.server;version="${project.version}"
                        
                    
                
            
        
    

注意:

i)OSGI框架(OSGI Library)通过pom配置后自动manve刷新就可以自动在 Project Settings-> Modules 中自动生成 OSGI 配置了,包括OSGI Library也自设置了,这里无需手动修改其他OSGI配置,默认即可。根据pom自动生成的OSGI配置如下:

基于Maven构建OSGI应用(Maven和OSGI结合)_第4张图片

Configure OSGI Core Library 点击打开显示如下:

基于Maven构建OSGI应用(Maven和OSGI结合)_第5张图片

版本号就是pom中指定OSGI dependency 的版本。

ii)pom文件中配置打包插件使用:maven-bundle-plugin 插件,该插件是专门为OSGI打包提供的插件,但是它不能导出 META-INF 中的内容到 Export-Package jar 包中。也就是说使用 maven-bundle-plugin 插件打包导出的 bundle jar 包中的 manifest 只能通过 pom.xml 文件中的 maven-bundle-plugin 打包参数项来配置,不能直接指定使用自己项目中指定的 manifest 文件(指定了也不生效)。另外,Project Settings -> Modules 中的 Manifest Generation 配置也没有用。

另外,maven-bundle-plugin 打包插件支持了一个标签:
*;scope=compile|runtime
有了这个标签,可以直接把依赖的 jar 打入 bundle jar 包中去。注意:这种方式仅对第三方依赖(dependency)有效,例如 pom 中j加入 mysql-connector-java 驱动依赖:


  mysql
  mysql-connector-java
  8.0.15

打包生成的bundle jar包中查看内容(jar tf xxx.jar),只要配置了 Embed-Dependency,对于 定义的第三方依赖,都会打入目标bundle jar包中,直接把依赖的 mysql-connector-java-8.0.15.jar 文件导入进去了,位于根目录下:

基于Maven构建OSGI应用(Maven和OSGI结合)_第6张图片

但是,对于本地Lib库文件,例如下面这种依赖方式,Embed-Dependency 则无效,不会把 test-common-1.0.0.jar 打入bundle jar包中:

基于Maven构建OSGI应用(Maven和OSGI结合)_第7张图片

对于这种,可以使用另外一种方式,通过 Export-Package 导出。

还是用 mysql-connector-java 驱动来尝试,以本地Lib方式设置pom依赖(scope设置为system、并指定本地Lib文件路径),然后再设置 Export-Package 进行导出:


    com.xxx.osgi.helloworld.client;version="${project.version}",
    com.mysql.cj;version=8.0.32,
    com.mysql.jdbc;version=8.0.32

jar tf helloworld-client-1.0.0-SNAPSHOT.jar 查看bundle jar包结构如下:

基于Maven构建OSGI应用(Maven和OSGI结合)_第8张图片

 5)编译打包:

mvn clean package

执行命令,就会生成目标jar文件:

基于Maven构建OSGI应用(Maven和OSGI结合)_第9张图片

生成的jar内容结构查看,使用 jar tf jarFileName 命令查看:

e:\ws2\qf\helloworld\helloworld-client\target> jar tf helloworld-client-1.0.0-SNAPSHOT.jar

基于Maven构建OSGI应用(Maven和OSGI结合)_第10张图片

6)添加 debug / run 配置,可在idea中运行或调试:

为client和server分别添加一个 debug/run 配置,Bundle name配置中添加 4个 必须依赖的系统jar和各自子模块的jar:

基于Maven构建OSGI应用(Maven和OSGI结合)_第11张图片

添加 debug/run 配置并运行后,会自动生成  out 目录:

基于Maven构建OSGI应用(Maven和OSGI结合)_第12张图片

7)拷贝生成的 client & server bundle(jar) 到OSGI环境执行:

我本地Windows配置的OSGI运行环境位于:d:\osgi\equinox\

d:> cd d:\osgi\equinox\
d:\osgi\equinox> ls 
org.eclipse.osgi_3.18.600.v20231110-1900.jar
plugins
start.bat
d:\osgi\equinox> mkdir  my_bundles
d:\osgi\equinox> cp e:\ws2\qf\helloworld\helloworld-client\target\helloworld-client-1.0.0-SNAPSHOT.jar my_bundles\helloworld-client-1.0.0-SNAPSHOT.jar
d:\osgi\equinox> cp e:\ws2\qf\helloworld\helloworld-server\target\helloworld-server-1.0.0-SNAPSHOT.jar my_bundles\helloworld-server-1.0.0-SNAPSHOT.jar

基于Maven构建OSGI应用(Maven和OSGI结合)_第13张图片

8)执行bundles:

install & start bundles,server需要先启动、再启动client:

基于Maven构建OSGI应用(Maven和OSGI结合)_第14张图片

到此为止,基于Maven构建OSGI应用示例完毕。

注意:如果pom中指定8时编译报错:java: Compilation failed: internal java compiler error,报错截图如下:

基于Maven构建OSGI应用(Maven和OSGI结合)_第15张图片

检查下面几处相关设置是否正确:

1)检查File->Project Structure->Project Settings->Modules配置中的Dependencies->Module SDK

基于Maven构建OSGI应用(Maven和OSGI结合)_第16张图片

2)检查Settings->Buile,Execution,Deployment->Compiler->Java Compiler设置Module的Per-module bytecode version->Target bytecode version

基于Maven构建OSGI应用(Maven和OSGI结合)_第17张图片

如果 Per-module bytecode version -> Target bytecode version 不一致(我最初默认是1.5)、修改为一致(8),问题就解决了。

你可能感兴趣的:(开发,maven,java,数据库,OSGI)