一、Spring Boot可以和OSGi一起使用吗?
是的,可以Spring Boot
在OSGI容器中运行应用程序.
首先,您必须从Spring Boot jar
包转换到OSGI bundle
.
如果你正在使用,Maven
你可以用它org.apache.felix:maven-bundle-plugin
来做.
由于Spring Boot
依赖jar不是有效的OSGI
bundle,我们应该使用bnd
工具将它们作为有效的bundle,或者我们可以将它们嵌入到bundle本身中.
这可以通过maven-bundle-plugin
配置来完成,尤其是配置<Embed-Dependency>
.
但是,我们需要以Spring Boot
某种方式启动应用程序包.想法是启动Spring Boot 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);
}
}
还应该将上下文类加载器设置为加载bundle的OSGI类加载器Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
.这是必需的因为Spring
使用上下文类加载器.
相关示例代码地址:https://gitee.com/zsiyang/felix-demo
但是这样有个局限性,由于在OSGI中运行时缺少程序包扫描支持,因此Spring Boot的按批注自动映射功能不起作用。OSGI对于包开放配置粒度比较细,然后有人提出了另一种解决方案
诀窍是为SpringApplication实例提供适当的ResourcePatternResolver:
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);
}
}
另一种方案提议没有找到方案:
实际上有很多很好的理由将Spring Boot部署到OSGi中,主要的是性能,特别是如果你的Spring Boot服务是一个功能服务(即它启动,返回结果,结束)的启动性能.我目前在Spring Boot中进行beta测试的应用程序在部署到Equinox的约0.5秒内启动,而自行启动时为3.5秒.其他原因可能是与基于OSGi的应用程序或Java EE服务器的集成.
也就是说,你也可以从Spring Boot运行OSGi,出于性能原因,我可能会赞成将Concierge作为一个超过Felix或Equinox的OSGi实现,因为它的体积很小(除非你的应用程序需要更大实现的所有功能).
另一种方法是将Spring Boot应用程序使用的Spring库包装到MSF4J(来自WSO2).这不需要太多工作,并且可以使您的内存使用率提高10倍,启动速度提高10倍.
二、boot项目打包插件
在研究时发现相关问题,有个比较头疼的东东还未完全研究,先行记录:
spring-boot-starter-parent.pom文件中 猜猜这东西最终影响了打包某些参数生成。osgi.ee=JavaSE9.0 由于插件组合进行打包,2.6.6版本更换后是1.8依赖,这里需要9的话很多引用都要变更,目前是用2.6.6进行替换测试,后面若有机会,继续研究,将更新文档内容
org.apache.maven.plugins.shade.resource.ManifestResourceTransformer
Setting Manifest Entries with the ManifestResourceTransformer
The ManifestResourceTransformer allows existing entries in the MANIFEST to be replaced and new entries added.
For example, the following sample sets
- the Main-Class entry to the value of the app.main.class property,
- the X-Compile-Source-JDK entry to the value of the maven.compile.source property and
- the X-Compile-Target-JDK entry to the value of the maven.compile.target property.
By default the ManifestResourceTransformer will relocate the following attributes:
- Export-Package
- Import-Package
- Provide-Capability
- Require-Capability
With additionalAttributes you can specify the attributes that need to be relocated too.
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>${app.main.class}</Main-Class> <X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK> <X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK> </manifestEntries> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
参考文献记录: