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

前端 未结 7 1273
闹比i
闹比i 2021-01-31 17:28

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

相关标签:
7条回答
  • 2021-01-31 17:44

    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 讨论(0)
  • 2021-01-31 17:46

    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

    0 讨论(0)
  • 2021-01-31 17:48

    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 讨论(0)
  • 2021-01-31 17:50

    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.

    0 讨论(0)
  • 2021-01-31 17:52

    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.

    0 讨论(0)
  • 2021-01-31 17:59

    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?

    0 讨论(0)
提交回复
热议问题