将多个SpringBoot / 微服务应用合并成一个SpringBoot应用

前言

当下在设计大型系统或网站时,为了满足系统的灵活性、扩展性、模块化、松耦合、高可用等特性,在技术架构选择时往往会选用微服务架构。独立服务的拆分会增加部署时机器资源的消耗。在轻量化部署场景的催化下,需要考虑中间件的缩减以及微服务应用的合并部署,已达到降低对服务器资源的依赖。

项目结构

我们的项目工程结构如下所示,其中xxx代表一个独立的微服务 ,整个工程由多个独立的微服务模块组成,这里只举例说明,没有列举完整的项目结构,api-xxx模块表示某个独立的微服务的后台管理能力,provider-xxx模块表示某个独立微服务对其它服务提供能力的模块。

- project-parent
    - api-xxx
    - provider-xxx

应用合并需要考虑的问题

因为系统整体基于微服务构建,在进行应用合并实现资源减配时,主要考虑将apiprovider应用进行合并,遇到的主要问题如下:

  1. apiprovider从业务角度属于同一个,所以重名的类较多,因此会导致Spring容器中的beanName重复
  2. ORM框架用的是JPAHibernate中的实体只有类名没有包路径,类名重复会导致JPA中的实体重复
  3. SpringMVC中注册的接口请求路径重复的问题
  4. apiprovider合并为一个服务后,其它应用通过RPC调用provider服务的服务名需要调整
  5. 其它一些由业务和技术特性决定的不具备普遍性的问题,这里不加赘述
    面临上面的问题,如果在一个SpringBoot模块中,直接通过Mavenapi-xxx模块provider-xxx模块引入后启动肯定会报错的。

应用合并合并

基于以上问题,理想状态是在一个JVM里面启动两个Spring容器,分别对应apiprovider,减少对服务器资源需求的同时最大程度保留原有的技术架构。
支持多个应用同时启动的容器类,这是一个抽象类,需要由具体启动的应用继承后设置应用名称和SpringBoot的Application类:

public abstract class MultipleServiceRunner {
   

    private ConfigurableApplicationContext applicationContext;

    private final String applicationName;

    private final Class<?>[] applicationClasses;

    private String[] args;

    private final static Object lock = new Object();

    private Boolean wait = Boolean.FALSE;

    public MultipleServiceRunner(String applicationName, Class<?>... applicationClasses) {
   
        this.applicationName = applicationName;
        this.applicationClasses = applicationClasses;
    }

    public void setArgs(String[] args) {
   
        this.args = args;
    }

    public void run() {
   
        if(applicationContext != null) {
   
            throw new IllegalStateException("AppContext must be null to run this backend");
        }
        runBackendInThread();
        waitUntilBackendIsStarted();
    }

    private void waitUntilBackendIsStarted() {
   
        try {
   
            synchronized (lock) {
   
                if(wait) {
   
                    lock.wait();
                }
            }
        } catch (InterruptedException e) {
   
            throw new IllegalStateException(e);
        }
    }

    private void runBackendInThread() {
   
        final Thread runnerThread = new ApplicationRunner(applicationName);
        wait = Boolean.TRUE;
        runnerThread.setContextClassLoader(applicationClasses[0].getClassLoader());
        runnerThread.start();
    }

    public void stop() {
   
        if (Optional.ofNullable(applicationContext).isPresent()) {
   
            SpringApplication.exit(applicationContext);
            applicationContext = null;
        }
    }

    protected class ApplicationRunner extends Thread {
   

        public ApplicationRunner(String name) {
   
            super(name
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值