gpt4 book ai didi

Spring Boot 使用自动配置创建多个(正常运行的)webmvc 应用程序

转载 作者:IT老高 更新时间:2023-10-28 13:45:23 26 4
gpt4 key购买 nike

更新

我的问题是如何在 spring boot 中初始化一个隔离的 spring webmvc web-app。隔离的 Web 应用程序应该:

  1. 不应在应用程序类中自行初始化。我们想通过自动配置在 starter pom 中执行这些操作。我们有多个这样的网络应用,我们需要自动配置的灵 active 。
  2. 能够使用以下接口(interface)进行 self 定制:WebSecurityConfigurer(我们有多个网络应用,每个都有以自己的方式安全)和 EmbeddedServletContainerCustomizer(到设置 servlet 的上下文路径)。
  3. 我们需要隔离特定于某些网络应用的 bean,并且不希望它们进入父上下文。

进展

下面的配置类在我的 META-INF/spring.factories 中列出。

以下策略不会导致正常运行的 web-mvc servlet。未设置上下文路径,也未自定义安全性。我的预感是我需要包含某些 webmvc bean,它们处理上下文并根据存在的 bean 自动配置——类似于我通过包含 PropertySourcesPlaceholderConfigurer.class 使基于引导的属性占位符配置工作的方式。

@Configuration
@AutoConfigureAfter(DaoServicesConfiguration.class)
public class MyServletConfiguration {
@Autowired
ApplicationContext parentApplicationContext;

@Bean
public ServletRegistrationBean myApi() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setParent(parentApplicationContext);
applicationContext.register(PropertySourcesPlaceholderConfigurer.class);
// a few more classes registered. These classes cannot be added to
// the parent application context.
// includes implementations of
// WebSecurityConfigurerAdapter
// EmbeddedServletContainerCustomizer

applicationContext.scan(
// a few packages
);

DispatcherServlet ds = new DispatcherServlet();
ds.setApplicationContext(applicationContext);

ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(ds, true, "/my_api/*");
servletRegistrationBean.setName("my_api");
servletRegistrationBean.setLoadOnStartup(1);
return servletRegistrationBean;
}
}

最佳答案

我们在使用 Boot 时遇到了类似的问题(创建一个带有父上下文的多 servlet 应用程序),我们通过以下方式解决了它:

1.创建您的父 Spring 配置,它将包含您要共享的所有父 bean。像这样的:

@EnableAutoConfiguration(
exclude = {
//use this section if your want to exclude some autoconfigs (from Boot) for example MongoDB if you already have your own
}
)
@Import(ParentConfig.class)//You can use here many clasess from you parent context
@PropertySource({"classpath:/properties/application.properties"})
@EnableDiscoveryClient
public class BootConfiguration {
}

2.创建将确定您的特定应用程序模块类型的类型(例如,您的情况是 REST 或 SOAP)。此外,您可以在此处指定所需的上下文路径或其他应用程序特定数据(我将在下面展示如何使用它):

public final class AppModule {

private AppType type;

private String name;

private String contextPath;

private String rootPath;

private Class<?> configurationClass;

public AppModule() {
}

public AppModule(AppType type, String name, String contextPath, Class<?> configurationClass) {
this.type = type;
this.name = name;
this.contextPath = contextPath;
this.configurationClass = configurationClass;
}

public AppType getType() {
return type;
}

public void setType(AppType type) {
this.type = type;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getRootPath() {
return rootPath;
}

public AppModule withRootPath(String rootPath) {
this.rootPath = rootPath;
return this;
}

public String getContextPath() {
return contextPath;
}

public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}

public Class<?> getConfigurationClass() {
return configurationClass;
}

public void setConfigurationClass(Class<?> configurationClass) {
this.configurationClass = configurationClass;
}

public enum AppType {
REST,
SOAP
}
}

3.为您的整个应用创建启动应用初始化程序:

public class BootAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

private List<AppModule> modules = new ArrayList<>();

BootAppContextInitializer(List<AppModule> modules) {
this.modules = modules;
}

@Override
public void initialize(ConfigurableApplicationContext ctx) {

for (ServletRegistrationBean bean : servletRegs(ctx)) {
ctx.getBeanFactory()
.registerSingleton(bean.getServletName() + "Bean", bean);
}
}

private List<ServletRegistrationBean> servletRegs(ApplicationContext parentContext) {

List<ServletRegistrationBean> beans = new ArrayList<>();

for (AppModule module: modules) {

ServletRegistrationBean regBean;

switch (module.getType()) {
case REST:
regBean = createRestServlet(parentContext, module);
break;
case SOAP:
regBean = createSoapServlet(parentContext, module);
break;
default:
throw new RuntimeException("Not supported AppType");
}

beans.add(regBean);
}

return beans;
}

private ServletRegistrationBean createRestServlet(ApplicationContext parentContext, AppModule module) {
WebApplicationContext ctx = createChildContext(parentContext, module.getName(), module.getConfigurationClass());
//Create and init MessageDispatcherServlet for REST
//Also here you can init app specific data from AppModule, for example,
//you can specify context path in the follwing way
//servletRegistrationBean.addUrlMappings(module.getContextPath() + module.getRootPath());
}

private ServletRegistrationBean createSoapServlet(ApplicationContext parentContext, AppModule module) {
WebApplicationContext ctx = createChildContext(parentContext, module.getName(), module.getConfigurationClass());
//Create and init MessageDispatcherServlet for SOAP
//Also here you can init app specific data from AppModule, for example,
//you can specify context path in the follwing way
//servletRegistrationBean.addUrlMappings(module.getContextPath() + module.getRootPath());
}

private WebApplicationContext createChildContext(ApplicationContext parentContext, String name,
Class<?> configuration) {
AnnotationConfigEmbeddedWebApplicationContext ctx = new AnnotationConfigEmbeddedWebApplicationContext();
ctx.setDisplayName(name + "Context");
ctx.setParent(parentContext);
ctx.register(configuration);

Properties source = new Properties();
source.setProperty("APP_SERVLET_NAME", name);
PropertiesPropertySource ps = new PropertiesPropertySource("MC_ENV_PROPS", source);

ctx.getEnvironment()
.getPropertySources()
.addLast(ps);

return ctx;
}
}

4.创建抽象配置类,其中将包含特定于子的 bean 以及您不能或不想通过父上下文共享的所有内容。在这里,您可以为您的特定应用模块指定所有必需的接口(interface),例如 WebSecurityConfigurerEmbeddedServletContainerCustomizer:

/*Example for REST app*/
@EnableWebMvc
@ComponentScan(basePackages = {
"com.company.package1",
"com.company.web.rest"})
@Import(SomeCommonButChildSpecificConfiguration.class)
public abstract class RestAppConfiguration extends WebMvcConfigurationSupport {

//Some custom logic for your all REST apps

@Autowired
private LogRawRequestInterceptor logRawRequestInterceptor;

@Autowired
private LogInterceptor logInterceptor;

@Autowired
private ErrorRegister errorRegister;

@Autowired
private Sender sender;

@PostConstruct
public void setup() {
errorRegister.setSender(sender);
}

@Override
public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(logRawRequestInterceptor);
registry.addInterceptor(scopeInterceptor);
}

@Override
public void setServletContext(ServletContext servletContext) {
super.setServletContext(servletContext);
}
}

/*Example for SOAP app*/
@EnableWs
@ComponentScan(basePackages = {"com.company.web.soap"})
@Import(SomeCommonButChildSpecificConfiguration.class)
public abstract class SoapAppConfiguration implements ApplicationContextAware {

//Some custom logic for your all SOAP apps

private boolean logGateWay = false;

protected ApplicationContext applicationContext;

@Autowired
private Sender sender;

@Autowired
private ErrorRegister errorRegister;

@Autowired
protected WsActivityIdInterceptor activityIdInterceptor;

@Autowired
protected WsAuthenticationInterceptor authenticationInterceptor;

@PostConstruct
public void setup() {
errorRegister.setSender(sender);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

/**
* Setup preconditions e.g. interceptor deactivation
*/
protected void setupPrecondition() {
}

public boolean isLogGateWay() {
return logGateWay;
}

public void setLogGateWay(boolean logGateWay) {
this.logGateWay = logGateWay;
}

public abstract Wsdl11Definition defaultWsdl11Definition();
}

5.创建将编译整个应用程序的入口点类:

public final class Entrypoint {

public static void start(String applicationName, String[] args, AppModule... modules) {
System.setProperty("spring.application.name", applicationName);
build(new SpringApplicationBuilder(), modules).run(args);
}

private static SpringApplicationBuilder build(SpringApplicationBuilder builder, AppModule[] modules) {
return builder
.initializers(
new LoggingContextInitializer(),
new BootAppContextInitializer(Arrays.asList(modules))
)
.sources(BootConfiguration.class)
.web(true)
.bannerMode(Banner.Mode.OFF)
.logStartupInfo(true);
}
}

现在一切准备就绪,分两步启动我们的 super 多应用启动:

1.初始化您的子应用,例如 REST 和 SOAP:

//REST module
@ComponentScan(basePackages = {"com.module1.package.*"})
public class Module1Config extends RestAppConfiguration {
//here you can specify all your child's Beans and etc
}

//SOAP module
@ComponentScan(
basePackages = {"com.module2.package.*"})
public class Module2Configuration extends SoapAppConfiguration {

@Override
@Bean(name = "service")
public Wsdl11Definition defaultWsdl11Definition() {
ClassPathResource wsdlRes = new ClassPathResource("wsdl/Your_WSDL.wsdl");
return new SimpleWsdl11Definition(wsdlRes);
}

@Override
protected void setupPrecondition() {
super.setupPrecondition();
setLogGateWay(true);
activityIdInterceptor.setEnabled(true);
}
}

2.准备入口点并作为启动应用程序运行:公共(public)类应用程序{

public static void main(String[] args) throws Exception {
Entrypoint.start("module1",args,
new AppModule(AppModule.AppType.REST, "module1", "/module1/*", Module1Configuration.class),
new AppModule(AppModule.AppType.SOAP, "module2", "module2", Module2Configuration.class)
);
}

}

享受^_^

有用的链接:

关于Spring Boot 使用自动配置创建多个(正常运行的)webmvc 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35095326/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com