【问题标题】:Running multiple Spring boot applications on same JVM在同一个 JVM 上运行多个 Spring Boot 应用程序
【发布时间】:2015-07-26 11:00:36
【问题描述】:

我有一个多 Maven 模块 Spring Boot 项目,结构如下:

parent
   |_ pom.xml
   |_ webservices
        |_ src/main/java
             |_ webservices
                  |_ WebServicesConfig.java
                  |_ WebServicesStarter.java
                  |_ GlobalPropertiesLoader.java
        |_ pom.xml
   |_ backend
        |_ src/main/java
             |_ backend
                  |_ BackendStarter.java
        |_ pom.xml
   |_ commons
        |_ src/main/java
             |_ commons
                  |_ GlobalPropertiesDAO.java
                  |_ GlobalPropertiesRepository.java
                  |_ CommonsConfig.java;
        |_ pom.xml

Web 服务和后端都是独立的 Spring 引导应用程序(它们生成一个 jar 文件,我用它来启动它们)并且它们依赖于 commons 模块。所以我在 web 服务和后端的 pom.xml 中包含了 commons 作为依赖项。

关于启动我的应用程序我有几个问题。

  1. 如何在单个 JVM 中同时启动后端和 Web 服务? (在同一个端口上)
  2. 我想在我的后端和 Web 服务项目中自动连接 GlobalPropertiesRepository(位于 commons 项目中)。我该怎么做呢?我可以跨不同的模块自动接线吗?仅仅导入公共资源是行不通的。它会引发“无 bean 定义错误”。我认为这是因为如果我导入 GlobalPropertiesRepository,Spring 容器不会启动它。

============= 更新 =============

为应用程序添加我的配置类:

commons 应用程序现在有一个空的 Configuration 类,因为那里只有我的 Repository 类。下面是空的配置类:

package commons;

import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonsConfig {

}

这是 GlobalPropertiesRepository:

package commons;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GlobalPropertiesRepository extends CrudRepository<GlobalPropertiesDAO, Long>{
}

以下是 Web 服务应用程序中必要的类:

入门类:

package webservices;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;

@SpringBootApplication
@EnableJpaRepositories
@ComponentScan({"commons", "webservices"})
public class WebServicesStarter {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(WebServicesStarter.class, args);

        ClassPathScanningCandidateComponentProvider provider =
                new ClassPathScanningCandidateComponentProvider(true);
    }

}

配置类:

package webservices;


import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import commons.CommonsConfig;

@Configuration
@Import(CommonsConfig.class)
public class WebServicesConfig {

    @Autowired CommonsConfig commonsConfig;
    public WebServicesConfig() {
    }
}

以及我尝试自动装配存储库的类:

package webservices;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import commons.GlobalPropertiesDAO;
import commons.GlobalPropertiesRepository;

@Component
@Scope("singleton")
public class GlobalPropertiesLoader {

    @Autowired
    public GlobalPropertiesRepository globalPropertiesRepository;

    private GlobalPropertiesDAO globalProperties;

    @PostConstruct
    public void init(){
        globalProperties = globalPropertiesRepository.findOne(1L);
    }

    public GlobalPropertiesDAO getGlobalProperties(){
        return globalProperties;
    }

}

这是我得到的错误:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: public commons.GlobalPropertiesRepository webservices.GlobalPropertiesLoader.globalPropertiesRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [commons.GlobalPropertiesRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)

谢谢。

【问题讨论】:

  • 如果您已经将 commons 模块作为 maven 依赖包含在 webservices 模块中,那么您不需要运行这两个模块。 Webservices 模块将可以访问公共依赖项。如果要自动装配存储库,首先需要从公共模块中导入配置类。例如,参见 [this] (docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/…)
  • @jrao77 谢谢。但我需要启动两个单独的应用程序。我之前已经简化了我的问题。我现在已经编辑了我的问题。
  • 我不确定是否可以这样做。您可以尝试将它们打包为 War(Spring boot 对此提供支持)并将它们放入同一个容器中?例如docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
  • 好的,我试试。但我仍然无法为另一个应用程序自动装配存储库。我尝试从另一个应用程序@importing 配置类,但我没有在配置类中声明存储库。所以我不认为这是要走的路。我的问题与此类似:stackoverflow.com/questions/22442822/…。我已经做了那个问题中建议的任何事情,但它仍然不起作用。
  • 您能否分享您的 @Configuration 类以用于存储库设置以及您将其连接到的后端模块及其配置?

标签: maven spring-boot spring-data-jpa


【解决方案1】:

我想我知道是什么导致了错误。

在您的应用入门类中,即使您有 @ComponentScan({"commons", "webservices"}) 出于某种原因,@Repository bean 也会被忽略。我认为问题出在 ClassPathBeanDefinitionScanner 类中。根据文档JavaDoc,它确实声明默认情况下它将扫描所有组件,包括@Repository。但是,当它识别存储库接口时,它会在方法 isCandidateComponent 中再次检查失败。 (如果您查看源代码)

所以当你启用调试时我们会得到这个日志

2015-05-18 11:10:13.399 DEBUG 67917 --- [main] oscaClassPathBeanDefinitionScanner:因为不是具体的顶级类而被忽略:文件 [****/jpa- test/dl/target/classes/commons/GlobalPropertiesRepository.class]

此外,因为EnableJpaRepositories 只扫描它声明的包,所以存储库没有被初始化。

如果您设置baseClassPackage(类型安全)属性,如@EnableJpaRepositories(basePackageClasses = GlobalPropertiesRepository.class),则存储库会被初始化。还要确保添加@EntityScan(basePackageClasses = GlobalPropertiesDAO.class)

【讨论】:

  • 哇非常感谢。这行得通。我从来不知道我们有basePackages 和'@EnableJPARepositories'。我使用basePackages 而不是basePackageClasses。另外,为什么我需要添加 @EntityScan ?没有它似乎也能工作。
  • @EntityScan 用于扫描 JPA 实体。当我在测试时,它抱怨 GlobalPropertiesDAO(我作为实体创建)没有得到管理。所以我认为你可能会遇到类似的问题。是的 basePackages 也可以,但它是一个字符串值,很容易出错:)
猜你喜欢
  • 2017-02-23
  • 2015-12-30
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
相关资源
最近更新 更多