Can Spring Boot be used with OSGi? If not, any plans to have an OSGi Spring Boot (Apache Felix or Eclipse Equinox)? In my opinion, cloud applications must be highly modular and updatable like OSGi offers.
-
See my answer https://stackoverflow.com/a/53518521/3503685 with working demo – StasKolodyuk Nov 28 '18 at 11:36
7 Answers
Yes, it's possible to run Spring Boot
apps in OSGI container.
First of all, you'll have to switch from Spring Boot jar
packaging to OSGI bundle
.
If you're using Maven
you can use org.apache.felix:maven-bundle-plugin
for doing that.
As Spring Boot
dependency jars are not valid OSGI
bundles, we should either make them valid bundles with bnd
tool or we can embed them into the bundle itself. That can be done with maven-bundle-plugin
configuration, particularly with <Embed-Dependency>
.
However, we need to start the bundle with Spring Boot
app somehow. The idea is to start Spring Boot in BundleActivator
:
@Import(AppConfig.class)
@SpringBootConfiguration
@EnableAutoConfiguration
public class SpringBootBundleActivator implements BundleActivator {
ConfigurableApplicationContext appContext;
@Override
public void start(BundleContext bundleContext) {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
appContext = SpringApplication.run(SpringBootBundleActivator.class);
}
@Override
public void stop(BundleContext bundleContext) {
SpringApplication.exit(appContext, () -> 0);
}
}
You should also set context classloader to an OSGI classloader loading the bundle by Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
.
That is required because Spring
uses context classloader.
You can see this in action in my demo repo: https://github.com/StasKolodyuk/osgi-spring-boot-demo

- 4,256
- 2
- 32
- 41
-
Works great, thanks for a solution. But only with kind of "static" routes. Springboot cannot find resources in bundles (java.io.FileNotFoundException: URL [bundle://221.0:1/by/kolodyuk/osgi/springboot/] cannot be resolved to absolute file path because it does not reside in the file system: bundle://221.0:1/by/kolodyuk/osgi/springboot/) Did you manage to find workaround? – Dmitry Andrievsky Dec 21 '18 at 08:05
-
@DmitryAndrievsky for which kind of resources did you faced that? Was that resource residing in another bundle? – StasKolodyuk Dec 26 '18 at 11:06
-
@StasKolodyuk for anything related to bundle scan. Resource was in the same bundle. Spring tries to scan resources, and fails with exception mentioned above. here's an example (based on your code), that is assumed to be auto-handled, but actually it is not @ RestController public class SimpleController { @ GetMapping("/simple") public String index() { return "some text"; } } – Dmitry Andrievsky Dec 27 '18 at 12:14
-
And instead of using @ Configuration attribute (with additional config classes) I tried just mark BundleActivator as @ SpringBootApplication. If it makes sense, I can provide example that works when run as SB app (java -jar ...), but fails in OSGI – Dmitry Andrievsky Dec 27 '18 at 12:16
-
1@DmitryAndrievsky, yeah, component scanning doesn't work properly. You need to use configuration classes and import beans manually. I faced that issue, dig down to `PathMatchingResourcePatternResolver` which doesn't work properly in OSGI bundles.There's an OSGI implementation here https://docs.spring.io/spring-osgi/snapshot-site/1.1.x/xref/org/springframework/osgi/io/OsgiBundleResourcePatternResolver.html However, you need to hack in `Spring Boot` somehow to make it load an OSGI version but I didn't go that far. – StasKolodyuk Dec 27 '18 at 15:03
-
1Finally solved. Trick is to provide org.springframework.osgi.io.OsgiBundleResourcePatternResolver (not OsgiBundleResourceLoader !) as ResourceLoader to SpringApplication class (https://github.com/dimmik/osgi-spring-boot-demo/blob/4f9668860443b8ef6402e2ebc5e3144d9c3eb35d/src/main/java/by/kolodyuk/osgi/springboot/SpringBootBundleActivator.java#L45). Here is a working example https://github.com/dimmik/osgi-spring-boot-demo URL is available at http://localhost:9015/simple (should produce "some text") after installing and starting bundle – Dmitry Andrievsky Dec 28 '18 at 10:42
-
Correction (because of new commits): resource loader: https://github.com/dimmik/osgi-spring-boot-demo/blob/5c1e2d6d4bc95a86558f19c361f0b5d4f599b100/src/main/java/by/kolodyuk/osgi/springboot/SpringBootBundleActivator.java#L27 Text to be produced on http://localhost:9015/simple : "some text. Means that scan works. Finally." – Dmitry Andrievsky Dec 28 '18 at 11:12
I think it worth posting as separate answer (not everyone reads all comments to answers).
Excellent solution from @StasKolodyuk gives a way to run Spring Boot application in an OSGI environment.
But with limitation: Spring Boot's auto-mapping by annotation does not work because of lack of package scan support when run in OSGI.
Here is another trick, that finally allows Spring Boot app with components to be auto-taken from your code to be run in OSGI (I tested in Karaf).
Functional example is available at https://github.com/dimmik/osgi-spring-boot-demo
The trick is to provide appropriate ResourcePatternResolver to SpringApplication instance:
package by.kolodyuk.osgi.springboot;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.osgi.io.OsgiBundleResourcePatternResolver;
@SpringBootApplication
public class SpringBootBundleActivator implements BundleActivator {
ConfigurableApplicationContext appContext;
@Override
public void start(BundleContext bundleContext) {
// Set context classloader (main trick, to enable SpringBoot start at the first place)
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
// trick to enable scan: get osgi resource pattern resolver
OsgiBundleResourcePatternResolver resourceResolver = new OsgiBundleResourcePatternResolver(bundleContext.getBundle());
// and provide it to spring application
appContext = new SpringApplication(resourceResolver, SpringBootBundleActivator.class).run();
}
@Override
public void stop(BundleContext bundleContext) {
SpringApplication.exit(appContext, () -> 0);
}
public static void main(String[] args) {
SpringApplication.run(SpringBootBundleActivator.class);
}
}

- 1,803
- 17
- 20
-
Hi, how can one get bundleContext or inject List of services inside Spring Boot's controller class? – user218046 Jan 28 '19 at 11:15
-
I have tried this solution with Spring Boot 2.1.4 but it seems that it doesn't work. It doesn't load my application.properties. Have you tried upgrading Spring Boot? – NikosDim Apr 25 '19 at 20:04
One possibility is to embed OSGi into your Spring Boot Application, to make some parts of your application accessible through the framework. See https://stackoverflow.com/a/4673904/173101 to see how you can start OSGi programmatically.
But in general there is nothing like "OSGi-Support". OSGi can be integrated into every Java-Application and, vice versa, you can package every Java-Code (also your Spring-Boot application) into an OSGi-bundle to start it within an OSGi container (although it probably wouldn't make much sense at all).

- 1
- 1

- 9,525
- 1
- 26
- 38
-
4I have question for your answer. You wrote that every Java Code (also Spring-Boot app) can be packaged into OSGi-bundle to start it within an OSGi container. The question is, how to package a Spring-Boot app into OSGi-bundle? – xmlParser Mar 09 '18 at 13:53
-
@xmlParser, see my answer stackoverflow.com/a/53518521/3503685 with working demo – StasKolodyuk Nov 28 '18 at 12:41
There's actually plenty of good reasons for deploying Spring Boot into OSGi, the main one being performance, particularly startup performance if your Spring Boot service is a functional service (i.e. it starts, returns results, ends). An application I'm currently beta testing in Spring Boot starts up in ~ 0.5 seconds deployed to Equinox versus 3.5 seconds on its own. Other reasons might be integration to an OSGi based application or Java EE server.
That said, you can also run OSGi from Spring Boot, for performance reasons I would probably favour Concierge as an OSGi implementation over Felix or Equinox, simply due to its small size (unless your app needs all the features of the bigger implementations.
Another alternative would be to wrap the Spring libraries used by your Spring Boot application into MSF4J (from WSO2). This doesn't take much work and can give you a 10x faster startup with 1/10th the memory usage.

- 61
- 1
- 1
No, it doesn't support OSGi. Spring Boot is aimed to create microservices as packaged applications with every dependency and even the servlet containers packaged in an executable JAR, so it's highly modular and updateable, without the need to provide and configure an OSGi container.

- 43,386
- 10
- 104
- 99
-
1What if one want to distribute a microservice app as a standalone app. In karat for instance. It would be nice to have each spring boot microservice deployed as OSGi bundle... – Patrice Aug 03 '17 at 15:54
Spring boot - well typical spring boot apps, are a little "fat" for osgi... if you are using the starter-web or jersey you'd need to add some sort of port determination scheme since ports are shared by all osgi "services" the system that the osgi runtime lives on.
The reason I would recommend avoiding spring-boot unless you can pare it down is the spring boot fat jar / war you create launches a sub class loader. This doesn't simplify things when you get confused about standard osgi class loader issues (com.whatever.someobject.MyClass not being the same in different bundles and classloaders because they are not "imported" from the same bundle that exports to all others) if there are any requirements for interbundle service communication.
I would suggest following guides to pare down to "spring boot core" if any exist you don't need the web listener and avoid all inter-bundle service interfaces that use any objects that aren't part of the standard imports (like core java se classes etc..). You only care about lifecycle right?

- 21
- 1
Why not stick to the microservice patterns and just launch your OSGI app as a separate application communicating with your spring-boot services over their REST API. On the OSGI application side you can use Jetty / Jersey etc to easily manage REST communication