Can Spring Boot be used with OSGi? If not, any plans to have an OSGi Spring Boot?

25.1k Views Asked by At

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.

7

There are 7 best solutions below

1
On

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.

2
On

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).

0
On

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?

7
On

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

2
On

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);
    }
}
0
On

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

0
On

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.