我有一个使用Spring Boot生成可执行的JAR的项目,该JAR公开了带有Spring Data REST的REST API。它还与Spring Security OAuth集成在一起。很好 我的问题是,
我想为REST API提供不同的模块,仅当具有JPA存储库的对应JAR位于类路径中(已将其定义为依赖项)时,才希望启用该模块。
问题是我希望他们彼此独立。我希望能够在具有不同映射的不同调度程序servlet下为它们提供服务,以便为每个资源指定不同的baseUri,并为资源发现使用不同的根URL。
我将尝试使其更加清晰:
API的模块A:
API模块B:
一个JAR,其中包含资源P和Q的PRespository和QRespository。
除此之外,我还可以拥有另一个调度程序servlet,其中包含/ oauth / 端点以及其他自定义控制器,并且安全配置必须对所有(/ )正常工作
我知道我可以通过ServletRegistrationBean定义更多的调度程序servlet,但是我不知道如何附加到每个不同的spring数据其余配置。
我还尝试通过在每个子上下文中使用定义每个调度程序servlet的配置,每个RepositoryRestMvcConfiguration以及每个@EnableJpaRepositories注释定义不同的要扫描的包,来通过SpringApplicationBuilder在分层应用程序上下文中实现此目的。无论如何,我什至无法加载上下文,因为它们不是作为WebApplicationContext创建的,因此失败了,因为没有ServletContext可用。
任何帮助/建议吗?提前致谢。
我前一段时间找到了解决方案,但忘了在这里分享,因此感谢Jan提醒我。
我通过在具有不同配置的新Web应用程序上下文( RepositoryRestMvcConfiguration )和一个公共父级(即Spring Boot应用程序的根应用程序上下文)中创建和注册多个调度程序servlet来解决了该问题。为了根据类路径中包含的不同jar自动启用API模块,我模拟了Spring Boot或多或少的功能。
该项目分为几个gradle模块。像这样:
模块 项目服务器 是主要的模块。它声明了对 project-api-autoconfigure 的依赖,同时排除了对 project-api- autoconfigure 对 project-module-?-api模块 的传递依赖。
在 project-server.gradle 内部:
dependencies { compile (project(':project-api-autoconfigure')) { exclude module: 'project-module-a-api' exclude module: 'project-module-b-api' ... } ... }
project-api-autoconfigure 依赖于所有API模块,因此依赖项在 project-api- autoconfigure.gradle 上看起来像这样:
dependencies { compile project(':project-module-a-api') compile project(':project-module-b-api') ... }
__我在 project-api-autoconfigure 中为每个API模块创建具有各自Web应用程序上下文的调度程序Servlet Bean,但是此配置取决于每个API模块jar中每个API模块的配置类。
我创建了一个抽象类,每个自动配置类都从该类继承:
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的自动配置类如下所示:
@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模块上 project-module-a-api , project-module-b-api …
它们可以是 RepositoryRestMvcConfiguration 或可以从中扩展,也可以是导入Spring Data REST配置的任何其他配置类。
最后但并非最不重要的一点是,我基于传递给gradle的属性来模拟Maven概要文件,在要加载的主模块 项目服务器 内创建了不同的gradle脚本。每个脚本都将需要包含的api模块声明为依赖项。看起来像这样:
- project-server /profiles/ profile-X.gradle profile-Y.gradle profile-Z.gradle
例如, profile-X 启用API模块A和B:
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模块。
配置文件是通过 project-server.gradle加载的 :
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" }
或多或少。希望对您有帮助。
干杯。