Чтобы узнать больше об использовании нескольких контекстов в одном приложении, я решил создать очень базовый c пример приложения, управляющего ресурсами публикации и использующего 2 дочерних контекста: один для Rest API, а другой - для MVC.
Приложение развернуто на отдельном сервере Tomcat 8.5 и прослушивает порт 8081.
Вот структура multi-context
приложения:
- мульти-контекст
- приложение
- Post. java
- PostService. java
- MultiContextApplication. java
- api
- ApiConfig. java
- PostApiController. java
- mvc
- MvcConfig. java
- PostController. java
1) Пакет Api (первый дочерний контекст)
ApiConfig. java
@Configuration
@EnableWebMvc
@ComponentScan
public class ApiConfig {
}
Отвечает только за загрузку PostApiController
в дочернем контексте API
PostApiController. java
@RestController
@AllArgsConstructor
@RequestMapping("/posts")
public class PostApiController {
private final PostService postService;
@PostMapping
public ResponseEntity<Post> createPost(@RequestBody Post post) {
return ok(postService.createPost(post.getTitle(), post.getContent()));
}
@GetMapping
public ResponseEntity<List<Post>> getAllPosts() {
return ok(postService.getAllPosts());
}
}
2) Mvc пакет (второй родственный контекст)
MvcConfig. java
@Configuration
@EnableWebMvc
@ComponentScan
public class MvcConfig {
}
Отвечает только за загрузку MVC PostController
в MVC дочернем контексте
PostController. java
@Controller
@AllArgsConstructor
@RequestMapping("/posts")
public class PostController {
private final PostService postService;
@GetMapping
public ModelAndView getAllPostsView() {
Map<String, Object> values = new HashMap<>();
values.put("posts", postService.getAllPosts());
return new ModelAndView("posts", values);
}
}
3) Пакет приложения (root контекст приложения)
Пакет, отвечающий за инициализацию root контекста приложения (загрузка общих компонентов (PostService), совместно используемых в каждом дочернем контексте) и инициализацию из 2 дочерних контекстов (API и MVC).
MultiContextApplication. java
@SpringBootApplication
public class MultiContextApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MultiContextApplication.class, args);
}
/**
* Root context initialization
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MultiContextApplication.class);
}
/**
* Rest API dispatcher servlet initialization
*/
@Bean(name = "apiDispatcherServlet")
public DispatcherServlet apiDispatcherServlet(WebApplicationContext webApplicationContext) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setParent(webApplicationContext);
applicationContext.register(ApiConfig.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setApplicationContext(applicationContext);
return dispatcherServlet;
}
/**
* Rest API child context initialization
*/
@Bean(name = "apiServletRegistrationBean")
public ServletRegistrationBean apiServletRegistrationBean(
@Qualifier("apiDispatcherServlet") DispatcherServlet apiDispatcherServlet) {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.addUrlMappings("/api/*");
servletRegistrationBean.setServlet(apiDispatcherServlet);
servletRegistrationBean.setLoadOnStartup(1);
servletRegistrationBean.setName("api-servlet");
return servletRegistrationBean;
}
/**
* MVC dispatcher servlet initialization
*/
@Bean(name = "mvcDispatcherServlet")
public DispatcherServlet mvcDispatcherServlet(WebApplicationContext webApplicationContext) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setParent(webApplicationContext);
applicationContext.register(MvcConfig.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setApplicationContext(applicationContext);
return dispatcherServlet;
}
/**
* MVC child context initialization
*/
@Bean(name = "mvcServletRegistrationBean")
public ServletRegistrationBean mvcServletRegistrationBean(
@Qualifier("mvcDispatcherServlet") DispatcherServlet mvcDispatcherServlet) {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.addUrlMappings("/mvc/*");
servletRegistrationBean.setServlet(mvcDispatcherServlet);
servletRegistrationBean.setLoadOnStartup(1);
servletRegistrationBean.setName("mvc-servlet");
return servletRegistrationBean;
}
}
Как и следовало ожидать, если входящий запрос http://localhost: 8081 / multi-context / api / posts он будет обрабатываться apiDispatcherServlet
(urlMapping = / api / *), и если входящий запрос http://localhost: 8081 / multi -context / mvc / posts он будет обработан mvcDispatcherServlet
(urlMapping = /mvc/*).
Проблема в том, что у меня есть 404
для обоих случаев, и я действительно не Understa и почему.
GET http://localhost:8081/multi-context/api/posts
{
"timestamp": "2020-07-14T00:28:33.461+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/multi-context/api/posts"
}
Выходной журнал:
2020-07-14 02:46:01.203 INFO 11120 --- [on(3)-127.0.0.1] c.i.m.app.MultiContextApplication : Starting MultiContextApplication v0.0.1-SNAPSHOT on L-5CD9474WTJ with PID 11120
2020-07-14 02:46:01.207 INFO 11120 --- [on(3)-127.0.0.1] c.i.m.app.MultiContextApplication : No active profile set, falling back to default profiles: default
2020-07-14 02:46:02.162 INFO 11120 --- [on(3)-127.0.0.1] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 919 ms
2020-07-14 02:46:02.626 INFO 11120 --- [on(3)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-07-14 02:46:02.771 INFO 11120 --- [on(3)-127.0.0.1] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2020-07-14 02:46:02.904 INFO 11120 --- [on(3)-127.0.0.1] c.i.m.app.MultiContextApplication : Started MultiContextApplication in 2.253 seconds (JVM running for 4.955)
2020-07-14 02:46:03.003 INFO 11120 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'api-servlet'
2020-07-14 02:46:03.084 INFO 11120 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Completed initialization in 81 ms
2020-07-14 02:46:03.086 INFO 11120 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'mvc-servlet'
2020-07-14 02:46:03.138 INFO 11120 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Completed initialization in 52 ms
2020-07-14 02:46:03.449 INFO 11120 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-07-14 02:46:03.451 INFO 11120 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
Как мы видим, контекст api-servlet
и контекст mvc-servlet
загружены успешно.
Возможно конфликт с контекстом по умолчанию dispatcherServlet
, но если это так, я не знаю, как решить проблему.