Классы, невидимые для OSGified Spring

Я делаю очень простое приложение, в котором пытаюсь запустить Spring bean с помощью osgi (apache felix). Мне удается прочитать файл spring-beans.xml, который я включаю в комплект, с таким кодом:

    ApplicationContext springContext = new GenericApplicationContext();
    InputStream in = thisBundle.getEntry("/spring-beans.xml").openStream();
    DefaultListableBeanFactory beans = new DefaultListableBeanFactory(springContext);
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beans);
    reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
    reader.loadBeanDefinitions(new InputStreamResource(in));
    beans.preInstantiateSingletons();
    in.close();
    return springContext;

Где это содержимое spring-beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 
<bean id="crazyClass" class="foo.bar.osgi.SpringInstantiatedBean">
    <property name="name" value="YES" />
</bean>
</beans>

Класс SpringInstantiatedBean имеет только одно свойство (имя) и геттер/сеттер для него. Это все нормально, если я запускаю его локально через основной класс, хотя путь для поиска файла spring-beans.xml немного отличается. Однако, когда я помещаю этот код на felix, вот что я получаю в своем активаторе:

Jun 7, 2012 4:37:40 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from resource loaded through InputStream
Jun 7, 2012 4:37:41 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2778c490: defining beans [crazyClass]; root of factory hierarchy
org.osgi.framework.BundleException: Activator start error in bundle foo.bar.osgi.OSGIProject [91].
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:2027)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:1895)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:944)
    at org.apache.felix.gogo.command.Basic.start(Basic.java:729)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)
    at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:82)
    at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:477)
    at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:403)
    at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
    at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183)
    at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120)
    at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89)
    at org.apache.felix.gogo.shell.Console.run(Console.java:62)
    at org.apache.felix.gogo.shell.Shell.console(Shell.java:203)
    at org.apache.felix.gogo.shell.Shell.gosh(Shell.java:128)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)
    at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:82)
    at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:477)
    at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:403)
    at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
    at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183)
    at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120)
    at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89)
    at org.apache.felix.gogo.shell.Activator.run(Activator.java:75)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [foo.bar.osgi.SpringInstantiatedBean] for bean with name 'crazyClass' defined in resource loaded through InputStream; nested exception is java.lang.ClassNotFoundException: foo.bar.osgi.SpringInstantiatedBean
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1262)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:576)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1331)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:897)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:566)
    at foo.bar.osgi.Activator.readSpringConfigAndInitContext(Activator.java:54)
    at foo.bar.osgi.Activator.start(Activator.java:29)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:641)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:1977)
    ... 32 more
Caused by: java.lang.ClassNotFoundException: foo.bar.osgi.SpringInstantiatedBean
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:257)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:417)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1283)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1254)
    ... 40 more
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [foo.bar.osgi.SpringInstantiatedBean] for bean with name 'crazyClass' defined in resource loaded through InputStream; nested exception is java.lang.ClassNotFoundException: foo.bar.osgi.SpringInstantiatedBean

Полная трассировка стека просто показывает мне, что в момент разрешения bean-компонентов внутренние компоненты spring не могут найти мой класс bean-компонента, что странно, потому что я могу без проблем создать его экземпляр в своем активаторе, например:

SpringInitializedBean bean = new SpringInitializedBean();

Это только предполагает, что это проблема с загрузчиком классов, но возможно ли, что загрузчик классов для BeanFactory не может получить доступ к моим классам? Если да, то как мне заставить его видеть мои классы? Кроме того, вот отрывок из моего pom.xml, где я настраиваю плагин пакета maven:

           <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.2.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-Activator>foo.bar.osgi.Activator</Bundle-Activator>
                        <Export-Package>foo.bar.osgi.osgi*</Export-Package>
                        <Private-Package>foo.bar.osgi*</Private-Package>
                        <Import-Package>*</Import-Package>
                        <Include-Resource>src/main/resources/spring-beans.xml</Include-Resource>
                    </instructions>
                </configuration>
            </plugin>

person Nikola Yovchev    schedule 07.06.2012    source источник
comment
Ваши частные и экспортные пакеты конфликтуют? Я не знаю, как плагин будет обрабатывать этот шаблон.   -  person JustinKSU    schedule 07.06.2012
comment
Попробуйте это stackoverflow.com/questions/8039931/   -  person Robin    schedule 07.06.2012


Ответы (2)


Похоже, ваша проблема заключается в том, что Spring пытается загрузить bean-компонент, используя Class.forName или аналогичные методы. Предполагается, что класс виден из системного загрузчика классов. Из-за того, что OSGi имеет сильное разделение классов с отдельными загрузчиками классов для каждого пакета, это предположение неверно.

Где находится «Фабрика бобов»? Находится ли он в системном пути к классам фреймворка OSGi или упакован в виде самого пакета? Если он находится в пакете, вы можете попробовать поиграть с предложениями Import-Package: и Export-Package в манифестах двух пакетов в качестве временного решения.

person pooh    schedule 08.06.2012
comment
Да, я обнаружил, что BeanFactory пытается загрузить классы с помощью загрузчика классов платформы OSGI, но похоже, что мои внутренние классы еще не отображаются во время метода запуска активатора, поэтому он не может их найти. Если я вручную установлю classLoadepri BeanFactory в качестве загрузчика классов Bundle, то он не сможет получить классы Spring. Я немного злюсь :) - person Nikola Yovchev; 09.06.2012
comment
Установка загрузчика классов BeanFactory в качестве загрузчика классов пакета — это шаг в правильном направлении. Теперь, почему он не находит весенние классы? Может быть, ваш пакет не импортирует их в свой манифест? Какая точная ошибка? - person pooh; 09.06.2012
comment
Сегодня я обнаружил, что борюсь с той же проблемой. Spring не видит классы моего собственного пакета, использующие аннотированные конфигурации Spring. Решение состоит в том, чтобы не использовать Spring или OSGi. - person anydoby; 06.10.2017

Две дешевые вещи, чтобы попытаться получить некоторую ясность:

  • Используйте динамический импорт. скажет вам, действительно ли это ваша проблема.
  • Попробуйте в Equinox вместо Felix. Феликс немного более строг, чем Эквинокс. Я знаю, что Весна и Равноденствие прекрасно работают в Деве. Опять же, само по себе это не решит вашу проблему, но немного сузит круг вопросов.
person Frank Lee    schedule 10.06.2012