问题
I have an existing application that exists as multiple Spring projects. Project A's Spring context XML file improts B's Spring context XML file using
<import resource="classpath*:/META-INF/spring/BContext.xml" />
However, it I get a FileNotFoundException
. I assume this is caused by the fact that the resource is not exposed by project B's bundle. I can access the classes, but not the file.
When researching this issue the common comment was to use OSGi services and inject the services instead of trying to inject the beans directly. However, since this is an existing application, I would like to avoid rewiring the entire thing.
Is there any way to tell OSGi to export the resource? I'm running ServiceMix on Karaf.
回答1:
It's just a classpath resource, so I would assume adding an appropriate Export-Package
directive would do the trick. That's definitely not the right way to do it, though. The path of that context file suggests that perhaps the project that contains BContext.xml is already set up to work with Spring Dynamic Modules. If so, then when you start that bundle, the Spring ApplicationContext is exported as a service. Look for it in your OSGi console.
Edit: In response to discussion in the comments:
I've never tried this myself, but theoretically it should be possible to use Spring DM's osgi namespace to make a bean reference to the OSGi service which is project B's ApplicationContext. Then, having a bean which is the ApplicationContext, you can use normal Spring configuration to extract beans from it using one of the getBean() methods. Note that you can use <constructor-arg ... />
to specify arguments to a factory method in a Spring config, as shown toward the bottom of this examples section.
回答2:
Loading the Spring Context and all of the implementation classes from another module is a huge violation of module encapsulation. If you are willing to do that, then it really makes no sense for A and B to be separate bundles at all, and you might as well make them a single bundle.
回答3:
The way you should do this is to utilize OSGi Services. You can register a service in Spring DM with the following (which is usually done in a seperate osgi-context.xml file to ensure that the code base is not dependent on OSGi for testing purposes. In this example, you would have a bean with the id clinic defined in BContext.xml, and which is referenced as an OSGi service
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/osgi"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<service id="osgiClinic" ref="clinic" interface="org.springframework.petclinic.repository.Clinic" />
</beans:beans>
Then in the consuming bundle's osgi-context.xml, you would reference the service. In the example below, you now have a bean called clinic that utilizes the code from the first bean.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/osgi"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<reference id="clinic" interface="org.springframework.petclinic.repository.Clinic"/>
</beans:beans>
This way of doing things will make sure you think about the dependencies between your bundles and only export those services that are necessary for other bundles.
来源:https://stackoverflow.com/questions/6749334/osgi-bundle-access-spring-context-file-from-another-bundle