我有一个使用Spring Boot生成可执行JAR的项目,该JAR使用Spring Data REST公开REST API。它还与Spring Security OAuth集成。这很好。我的问题如下,
我希望只有当具有JPA存储库的对应JAR位于类路径中时才能启用REST API的不同模块(它已被定义为依赖项)。
事情是我希望他们彼此独立。我希望能够在具有不同映射的不同调度程序servlet下为它们提供服务,这样我就可以为每个映射指定不同的baseUri,并为资源发现提供不同的根URL。
我会试着让它更清楚:
API的模块A:
API的模块B:
更多模块......
除此之外,我可以拥有另一个调度程序servlet,其中我保存/ oauth / *端点以及其他自定义控制器,并且安全配置必须适用于所有(/ *)
我知道我可以通过ServletRegistrationBean定义更多的调度程序servlet,但我不知道如何附加到每个不同的弹簧数据休息配置。
我也一直在尝试使用SpringApplicationBuilder进行分层应用程序上下文,方法是在每个子上下文中配置定义每个调度程序servlet的配置,每个RepositoryRestMvcConfiguration并使每个@EnableJpaRepositories注释定义要扫描的不同包。无论如何我甚至无法加载上下文,因为它们没有被创建为WebApplicationContext因此失败,因为没有可用的ServletContext。
任何帮助/建议?提前谢谢。
答案 0 :(得分:7)
我刚才找到了解决方案,但我忘了在这里分享,所以感谢Jan提醒我。
我通过使用具有不同配置的新Web应用程序上下文( RepositoryRestMvcConfiguration )创建和注册多个调度程序servlet以及作为Spring Boot应用程序的根应用程序上下文的公共父项来解决它。为了根据类路径中包含的不同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模块的配置类为条件的。每个API模块jar。
我创建并抽象了每个autoconfiguration类继承的类:
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 上, 项目模块-b-API ...
它们可以是 RepositoryRestMvcConfiguration ,也可以从它扩展,也可以是导入Spring Data REST配置的任何其他配置类。
最后但并非最不重要的是,我在主模块 project-server 中创建了不同的gradle脚本,以便根据传递给gradle的属性加载以模拟Maven配置文件。每个脚本都声明需要包含的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"
}
这或多或少都是。我希望它可以帮助你Jan。
干杯。