菜瓜:今天听到个名词“父子容器”,百度了一下,感觉概念有点空洞,这是什么核武器?
水稻:你说的是SpringMvc和Spring吧,其实只是一个概念而已,用来将两个容器做隔离,起到解耦的作用,其中子容器可以拿到父容器的bean,父容器拿不到子容器的。但是SpringBoot出来之后这个概念基本就被淡化掉,没有太大意义,SpringBoot中只有一个容器了。
菜瓜:能不能给个demo?
水稻:可以。由于现在SpringBoot已经大行其道,Mvc你可能接触的少,甚至没接触过。
早些年启动一个Mvc项目费老鼻子劲了,要配置各种Xml文件(Web.xml,spring.xml,spring-dispather.xml),然后开发完的项目要打成War包发到Tomcat容器中
现在可以直接引入Tomcat包,用main方法直接调起。为了调试方便,我就演示一个Pom引入Tomcat的例子
①启动类
package com.vip.qc.mvc;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.startup.Tomcat;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* 参考: * https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet
* <p>
* 嵌入tomcat,由Tomcat发起对Spring容器的初始化调用过程
* <p>
* - 启动过程
* * - Servlet规范,Servlet容器在启动之后会SPI加载META-INF/services目录下的实现类并调用其onStartup方法
* * - Spring遵循规范实现了ServletContainerInitializer接口。该接口在执行时会收集WebApplicationInitializer接口实现类并循环调用其onStartup方法
* * - 其中AbstractDispatcherServletInitializer
* * * - 将spring上下文放入ContextLoaderListener监听器,该监听会发起对refresh方法的调用
* * * - 注册dispatcherServlet,后续会由tomcat调用HttpServletBean的init方法,完成子容器的refresh调用
* *
*
* @author QuCheng on 2020/6/28.
*/
public class SpringWebStart {
public static void main(String[] args) {
Tomcat tomcat = new Tomcat();
try {
// 此处需要取一个目录
Context context = tomcat.addContext("http://www.likecs.com/", System.getProperty("java.io.tmp"));
context.addLifecycleListener((LifecycleListener) Class.forName(tomcat.getHost().getConfigClass()).newInstance());
tomcat.setPort(8081);
tomcat.start();
tomcat.getServer().await();
} catch (LifecycleException | ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
static class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
private final static String PACKAGE_PATH = "com.vip.qc.mvc.controller";
private final static String PACKAGE_PATH_CHILD = "com.vip.qc.mvc.service";
@Override
protected String[] getServletMappings() {
return new String[]{"http://www.likecs.com/"};
}
@Override
protected Class<?>[] getRootConfigClasses() {
// spring 父容器
return new Class[]{AppConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
// servlet 子容器
return new Class[]{ServletConfig.class};
}
@Configuration
@ComponentScan(value = PACKAGE_PATH_CHILD, excludeFilters = @ComponentScan.Filter(classes = Controller.class))
static class AppConfig {
}
@Configuration
@ComponentScan(value = PACKAGE_PATH, includeFilters = @ComponentScan.Filter(classes = Controller.class))
static class ServletConfig {
}
}
}