web-dev-qa-db-fra.com

Spring Boot peut-il être utilisé avec OSGi? Si ce n'est pas le cas, avez-vous des plans pour un démarrage OSGi Spring?

Spring Boot peut-il être utilisé avec OSGi? Si ce n'est pas le cas, avez-vous l'intention d'avoir un OSGi Spring Boot (Apache Felix ou Eclipse Equinox)? À mon avis, les applications cloud doivent être hautement modulaires et modifiables, comme le propose OSGi.

14
user3646774

Une possibilité consiste à intégrer OSGi à votre application de démarrage Spring afin de rendre certaines parties de votre application accessibles via le framework. Voir https://stackoverflow.com/a/4673904/173101 pour voir comment vous pouvez démarrer OSGi par programme.

Mais en général, rien de tel que "OSGi-Support". OSGi peut être intégré à toutes les applications Java et, inversement, vous pouvez conditionner chaque code Java (également votre application Spring-Boot) dans un ensemble OSGi pour le démarrer dans un conteneur OSGi (bien sens du tout).

6
Tom Seidel

Oui, il est possible d'exécuter des applications Spring Boot dans un conteneur OSGI.

Tout d’abord, vous devez passer de l’emballage Spring Boot jar à OSGI bundle.

Si vous utilisez Maven, vous pouvez utiliser org.Apache.felix:maven-bundle-plugin pour le faire. Comme les jarges de dépendance Spring Boot ne sont pas des ensembles OSGI valides, nous devons soit les transformer en ensembles valides avec l’outil bnd, soit les intégrer au kit lui-même. Cela peut être fait avec la configuration maven-bundle-plugin, en particulier avec <Embed-Dependency>.

Cependant, nous devons commencer le paquet avec Spring Boot app en quelque sorte. L'idée est de démarrer Spring Boot dans 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);
    }
}

Vous devez également définir le chargeur de classe de contexte sur un chargeur de classe OSGI chargeant le paquet par Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());. Cela est requis car Spring utilise le chargeur de classe de contexte.

Vous pouvez voir cela en action dans mon dépôt de démonstration: https://github.com/StasKolodyuk/osgi-spring-boot-demo

5
StasKolodyuk

Il existe de nombreuses bonnes raisons de déployer Spring Boot dans OSGi, la principale étant les performances, en particulier les performances de démarrage si votre service Spring Boot est un service fonctionnel (c’est-à-dire qu’il démarre, renvoie les résultats et se termine). Une application en cours de test bêta dans Spring Boot démarre en environ 0,5 seconde et déployée sous Equinox, au lieu de 3,5 secondes seule. D'autres raisons peuvent être l'intégration à une application OSGi ou à un serveur Java EE.

Cela dit, vous pouvez également exécuter OSGi à partir de Spring Boot. Pour des raisons de performances, je préférerais probablement Concierge comme implémentation OSGi à Felix ou Equinox, tout simplement en raison de sa petite taille (sauf si votre application a besoin de toutes les fonctionnalités des implémentations plus grandes.

Une autre solution consiste à envelopper les bibliothèques Spring utilisées par votre application Spring Boot dans MSF4J (à partir de WSO2). Cela ne prend pas beaucoup de travail et peut vous donner un démarrage 10x plus rapide avec 1/10ème de l'utilisation de la mémoire.

5
Andrew Glynn

Je pense que cela vaut la peine d'afficher une réponse séparée (tout le monde ne lit pas tous les commentaires aux réponses).

L’excellente solution de @StasKolodyuk permet d’exécuter l’application Spring Boot dans un environnement OSGI. 

Mais avec limitation: le mappage automatique par annotation de Spring Boot ne fonctionne pas faute de prise en charge de l'analyse de package lorsqu'il est exécuté dans OSGI.

Voici une autre astuce, qui permet enfin à l'application Spring Boot avec des composants de prendre automatiquement votre code dans un code OSGI (que j'ai testé avec Karaf).

Un exemple fonctionnel est disponible sur https://github.com/dimmik/osgi-spring-boot-demo

L'astuce consiste à fournir les ressources appropriées ResourcePatternResolver à l'instance SpringApplication:

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);
    }
}
3
Dmitry Andrievsky

Spring Boot - les applications de démarrage printanières typiques sont un peu "fatigantes" pour osgi ... si vous utilisez le starter-web ou le maillot, vous devez ajouter une sorte de schéma de détermination du port puisque les ports sont partagés par tous les osgi " services "le système sur lequel tourne le runtime osgi. 

La raison pour laquelle je recommanderais d'éviter Spring-Boot à moins que vous ne puissiez le réduire est que le bocal/botte de graisse pour démarrage de printemps que vous créez lance un chargeur de classe inférieure. Cela ne simplifie pas les choses lorsque vous vous trompez au sujet des problèmes de chargeur de classes osgi standard (com.witely.someobject.MyClass n'est pas identique dans différents bundles et chargeurs de classes car ils ne sont pas "importés" du même bundle que celui exporté vers tous les autres) s'il existe des exigences en matière de communication de service inter-groupements.

Je suggérerais de suivre les guides suivants pour "printemps de démarrage", s'il n'y en a pas, vous n'avez pas besoin de l'écouteur Web et évitez toutes les interfaces de service inter-bundle qui utilisent des objets ne faisant pas partie des importations standard (comme Java se classes etc ..). Vous ne vous souciez que du cycle de vie, n'est-ce pas? 

2
some random

Non, il ne supporte pas OSGi. Spring Boot vise à créer des microservices sous la forme d'applications packagées avec toutes les dépendances et même les conteneurs de servlets fournis dans un fichier JAR exécutable. Il est donc hautement modulaire et modifiable, sans qu'il soit nécessaire de fournir et de configurer un conteneur OSGi.

1
dunni