我有一个项目,它使用Spring生成一个可执行的JAR,该JAR使用Spring数据REST公开REST。它还与Security集成。效果很好。我的问题是,
我希望为REST提供不同的模块,只有当带有JPA存储库的通讯员JAR位于类路径中(它已被定义为依赖项)时,才能启用这些模块。
问题是我想让他们彼此独立。我希望能够在具有不同映射的不同dispatcher servlet中为它们提供服务,以便为每个映射指定不同的baseUri,并为资源发现指定不同的根URL。
我会尽量说得更清楚:
- 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.
- 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。
有什么帮助/建议吗?提前谢谢。
发布于 2015-02-13 12:00:29
我不久前找到了解决方案,但忘了在这里分享,所以感谢Jan提醒我这一点。
我通过创建和注册几个具有不同配置(RepositoryRestMvcConfiguration)的新web应用程序上下文的分派程序servlet和一个共同的父级( Spring应用程序的根应用程序上下文)来解决这个问题。为了自动启用API模块,取决于类路径中包含的不同jars,我或多或少地模拟了Spring所做的事情。
该项目分为几个分级模块。就像这样:
模块项目-服务器是主要的.它声明了一个依赖于项目-api-自动配置,同时它排除了项目-api-自动配置对项目-模块-?-api模块的传递依赖关系。
内部项目-server.gradle
dependencies {
compile (project(':project-api-autoconfigure')) {
exclude module: 'project-module-a-api'
exclude module: 'project-module-b-api'
...
}
...
}
项目- API -自动配置依赖于所有的api模块,因此依赖项将类似于project-api-autofigre.gradle
dependencies {
compile project(':project-module-a-api')
compile project(':project-module-b-api')
...
}
project自动配置是我为每个API模块创建带有自己的web应用程序上下文的dispatcher servlet的地方,但是这种配置取决于每个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模块项目-模块-a-api,项目-模块-b-api上.
它们可以是RepositoryRestMvcConfiguration,也可以从它扩展,也可以是导入Spring配置的任何其他配置类。
最后但并非最不重要的一点是,我在主模块项目中创建了不同的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模块。
配置文件以这种方式从项目-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"
}
这都差不多了。我希望它能帮到你。
干杯。
https://stackoverflow.com/questions/27319051
复制相似问题