首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Spring (JAR)具有多个调度器servlet,用于不同REST和Spring数据REST

Spring (JAR)具有多个调度器servlet,用于不同REST和Spring数据REST
EN

Stack Overflow用户
提问于 2014-12-05 15:17:14
回答 1查看 4.5K关注 0票数 7

我有一个项目,它使用Spring生成一个可执行的JAR,该JAR使用Spring数据REST公开REST。它还与Security集成。效果很好。我的问题是,

我希望为REST提供不同的模块,只有当带有JPA存储库的通讯员JAR位于类路径中(它已被定义为依赖项)时,才能启用这些模块。

问题是我想让他们彼此独立。我希望能够在具有不同映射的不同dispatcher servlet中为它们提供服务,以便为每个映射指定不同的baseUri,并为资源发现指定不同的根URL。

我会尽量说得更清楚:

  • API模块A:

代码语言:javascript
运行
复制
- A JAR containing for example XRespository and YRespository for resources X and Y.
- Dispatcher servlet A.
- Servlet mapping: /api/moduleA/
- Base URI for Spring Data REST: /api/moduleA/
- If I check URL /api/moduleA/ I should discover resources X and Y.

  • API模块B:

代码语言:javascript
运行
复制
- A JAR containing for example PRespository and QRespository for resources P and Q.
- Dispatcher servlet B.
- Servlet mapping: /api/moduleB/
- Base URI for Spring Data REST: /api/moduleB/
- If I check URL /api/moduleB/ I should discover resources P and Q.

  • 更多的模块..。

除此之外,我还可以使用另一个dispatcher servlet来保存/oauth/*端点以及其他自定义控制器,并且安全配置必须为所有人正常工作(/*)

我知道我可以通过ServletRegistrationBean定义更多的dispatcher servlet,但我不知道如何附加到每个不同的spring数据rest配置。

我还试图通过在每个子上下文中定义每个dispatcher servlet、每个RepositoryRestMvcConfiguration和每个定义要扫描的包的@EnableJpaRepositories注释的配置,使用分层应用程序上下文来实现这一点。无论如何,我甚至不能加载上下文,因为它们不是作为WebApplicationContext创建的,因此失败了,因为没有可用的ServletContext。

有什么帮助/建议吗?提前谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-02-13 12:00:29

我不久前找到了解决方案,但忘了在这里分享,所以感谢Jan提醒我这一点。

我通过创建和注册几个具有不同配置(RepositoryRestMvcConfiguration)的新web应用程序上下文的分派程序servlet和一个共同的父级( Spring应用程序的根应用程序上下文)来解决这个问题。为了自动启用API模块,取决于类路径中包含的不同jars,我或多或少地模拟了Spring所做的事情。

该项目分为几个分级模块。就像这样:

  • 项目服务器
  • project自动配置
  • 项目-模块-a-api
  • 项目-模块-b-api
  • ..。
  • 项目-模块-n-api

模块项目-服务器是主要的.它声明了一个依赖于项目-api-自动配置,同时它排除了项目-api-自动配置对项目-模块-?-api模块的传递依赖关系。

内部项目-server.gradle

代码语言:javascript
运行
复制
dependencies {
    compile (project(':project-api-autoconfigure')) {
        exclude module: 'project-module-a-api'
        exclude module: 'project-module-b-api'
        ...
    }
    ...
}

项目- API -自动配置依赖于所有的api模块,因此依赖项将类似于project-api-autofigre.gradle

代码语言:javascript
运行
复制
dependencies {
    compile project(':project-module-a-api')
    compile project(':project-module-b-api')
    ...
}

project自动配置是我为每个API模块创建带有自己的web应用程序上下文的dispatcher servlet的地方,但是这种配置取决于每个API模块jar中存在的每个API模块的配置类。

我创建和抽象了每个自动配置类继承的类:

代码语言:javascript
运行
复制
public abstract class AbstractApiModuleAutoConfiguration<T> {

    @Autowired
    protected ApplicationContext applicationContext;

    @Autowired
    protected ServerProperties server;

    @Autowired(required = false)
    protected MultipartConfigElement multipartConfig;

    @Value("${project.rest.base-api-path}")
    protected String baseApiPath;

    protected DispatcherServlet createApiModuleDispatcherServlet() {
        AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
        webContext.setParent(applicationContext);
        webContext.register(getApiModuleConfigurationClass());
        return new DispatcherServlet(webContext);
    }

    protected ServletRegistrationBean createApiModuleDispatcherServletRegistration(DispatcherServlet apiModuleDispatcherServlet) {
        ServletRegistrationBean registration = new ServletRegistrationBean(
                apiModuleDispatcherServlet,
                this.server.getServletMapping() + baseApiPath + "/" + getApiModulePath() + "/*");

        registration.setName(getApiModuleDispatcherServletBeanName());
        if (this.multipartConfig != null) {
            registration.setMultipartConfig(this.multipartConfig);
        }
        return registration;
    }

    protected abstract String getApiModuleDispatcherServletBeanName();

    protected abstract String getApiModulePath();

    protected abstract Class<T> getApiModuleConfigurationClass();

}

现在,模块A的自动配置类如下所示:

代码语言:javascript
运行
复制
@Configuration
@ConditionalOnClass(ApiModuleAConfiguration.class)
@ConditionalOnProperty(prefix = "project.moduleA.", value = "enabled")
public class ApiModuleAAutoConfiguration extends AbstractApiModuleAutoConfiguration<ApiModuleAConfiguration> {

    public static final String API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME = "apiModuleADispatcherServlet";
    public static final String API_MODULE_A_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "apiModuleADispatcherServletRegistration";

    @Value("${project.moduleA.path}")
    private String apiModuleAPath;

    @Bean(name = API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet apiModuleADispatcherServlet() {
        return createApiModuleDispatcherServlet();
    }

    @Bean(name = API_MODULE_A_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    public ServletRegistrationBean apiModuleADispatcherServletRegistration() {
        return createApiModuleDispatcherServletRegistration(apiModuleADispatcherServlet());
    }

    @Override
    protected String getApiModuleDispatcherServletBeanName() {
        return API_MODULE_A_DISPATCHER_SERVLET_BEAN_NAME;
    }

    @Override
    protected String getApiModulePath() {
        return apiModuleAPath;
    }

    @Override
    protected Class<ApiModuleAConfiguration> getApiModuleConfigurationClass() {
        return ApiModuleAConfiguration.class;
    }

}

现在,你的ApiModuleAConfiguration,ApiModuleBConfiguration..。配置类将在每个api模块项目-模块-a-api,项目-模块-b-api上.

它们可以是RepositoryRestMvcConfiguration,也可以从它扩展,也可以是导入Spring配置的任何其他配置类。

最后但并非最不重要的一点是,我在主模块项目中创建了不同的gradle脚本--基于传递给gradle以模拟Maven配置文件的属性来加载。每个脚本都将需要包含的api模块声明为依赖项。看起来是这样的:

代码语言:javascript
运行
复制
- project-server
    /profiles/
        profile-X.gradle
        profile-Y.gradle
        profile-Z.gradle

例如,profile-X支持API模块A和B:

代码语言:javascript
运行
复制
dependencies {
    compile project(':project-module-a-api')
    compile project(':project-module-b-api')
}

processResources {
    from 'src/main/resources/profiles/profile-X'
    include 'profile-x.properties'
    into 'build/resources/main'
}

其他配置文件可以启用不同的API模块。

配置文件以这种方式从项目-server.gradle加载

代码语言:javascript
运行
复制
loadProfile()

processResources {
    include '**/*'
    exclude 'profiles'
}

dependencies {
        compile (project(':project-api-autoconfigure')) {
            exclude module: 'project-module-a-api'
            exclude module: 'project-module-b-api'
            ...
        }
        ...
    }

...

def loadProfile() {
    def profile = hasProperty('profile') ? "${profile}" : "dev"
    println "Profile: " + profile
    apply from: "profiles/" + profile + ".gradle"
}

这都差不多了。我希望它能帮到你。

干杯。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27319051

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档