OSGI - 如何解决:ClassNotFoundException? (org.eclipse.osgi.internal.loader.BundleLoader.findClass)

Posted

技术标签:

【中文标题】OSGI - 如何解决:ClassNotFoundException? (org.eclipse.osgi.internal.loader.BundleLoader.findClass)【英文标题】:OSGI - How to solve: ClassNotFoundException? (org.eclipse.osgi.internal.loader.BundleLoader.findClass) 【发布时间】:2021-09-01 06:04:00 【问题描述】:

当使用三个包时 A = first.bundle B = second.bundle 和 C = third.bundle,其中 A 依赖于 B和C,C调用方法java.lang.Class.forName

时找不到B的类

是否在任何 pom.xml 文件中缺少配置或以任何其他方式为 bunlde C 的 ClassLoader 配备 B.SecondClass 类?

org.example.first.bundle.FirstClass

public void topLevelMethod() 
  ThirdClass thirdObject = new ThirdClass();
  thirdObject.resolveTheClassName("org.example.second.bundle.SecondClass")

org.example.third.bundle.ThirdClass

public <T> Class<T> resolveTheClassName(String className) throws ClassNotFoundException 
  return (Class<T>) Class.forName(className);

java.lang.ClassNotFoundException:在 org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:516) 上的 third.bundle_1.0.0.SNAPSHOT 找不到 org.example.second.bundle.SecondClass 在 org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:171) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 java.lang.Class.forName0(本机方法) 在 java.lang.Class.forName(Class.java:264) 在 org.example.third.bundle.ThirdClassA.getContentType(ThirdClassA.java:100) 在 org.example.third.bundle.ThirdClassB$ReceivingTask.run(ThirdClassB.java:135) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 在 java.lang.Thread.run(Thread.java:748)

first.bundle/pom.xml

<dependencies>
    <groupId>$project.groupId</groupId>
    <artifactId>second.package</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>provided</scope>
    <groupId>$project.groupId</groupId>
    <artifactId>third.package</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>provided</scope>
</dependencies>

second.bundle/pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Bundle-SymbolicName>$project.name</Bundle-SymbolicName>
                    <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                    <Embed-Directory>OSGI-INF/lib</Embed-Directory>
                    <Embed-Transitive>true</Embed-Transitive>
                    <Import-Package>
                        *;resolution:=optional
                    </Import-Package>
                    <Export-Package>
                        org.example.second.bundle
                    </Export-Packlage>
                </instructions>
            </configuration>
        </plugin>
    </plugins>
</build>

third.bundle/pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Bundle-SymbolicName>$project.name</Bundle-SymbolicName>
                    <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                    <Embed-Directory>OSGI-INF/lib</Embed-Directory>
                    <Embed-Transitive>true</Embed-Transitive>
                    <Import-Package>
                        *;resolution:=optional
                    </Import-Package>
                    <Export-Package>
                        org.example.third.bundle
                    </Export-Packlage>
                </instructions>
            </configuration>
        </plugin>
    </plugins>
</build>

【问题讨论】:

【参考方案1】:

类加载器配置在一个图中,每个导入的包都有边。因此,如果 C 没有 B 中的包的导入边缘,则 C 无法从 B 中的该包中类加载类。

如果 C 有来自 B 的对象,它可以在 Class.forName 调用中使用来自 B 的对象的类的类加载器。但通常不应该在 OSGi 中使用 Class.forName。使用 OSGi 服务会更好。然后 C 可以在 OSGi 服务注册表中找到感兴趣的对象。

【讨论】:

谢谢,我研究了原生 OSGI 方法并找到了解决方案【参考方案2】:

找到了解决办法!

public <T> Class<T> resolveTheClassName(String className) throws ClassNotFoundException 
  BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
        List<Class<?>> foundClasses = findClass(bundleContext, serializedContentType);
        if(foundClasses.isEmpty()) 
            return (Class<T>)Class.forName(serializedContentType);
         else 
            return (Class<T>)foundClasses.get(0);
        

private List<Class<?>> findClass(BundleContext context, String name) 
    List<Class<?>> result = new ArrayList<Class<?>>();
    for (Bundle b : context.getBundles()) 
        try 
            Class<?> c = b.loadClass(name);
            result.add(c);
         catch (ClassNotFoundException e) 
            // No problem, this bundle doesn't have the class
        
    
    return result;

How to load a class by classname string from OSGi runtime environment?

【讨论】:

以上是关于OSGI - 如何解决:ClassNotFoundException? (org.eclipse.osgi.internal.loader.BundleLoader.findClass)的主要内容,如果未能解决你的问题,请参考以下文章

Apache Karaf 和 OSGI 捆绑包

OSGI 缺少需求错误

python中是不是有类似于osgi试图在java中解决的要求?

maven管理jar包后依然找不到Jar包或者ClassNotFound的解决

是否存在对 OSGi 术语、框架及其关系的概述?

在 osgi 中使用 ucanaccess 时出错