【Spring】内嵌Tomcat&去Xml&调试Mvc
2021-05-01 22:29
标签:reference efi intercept handler art demo gets 遇到 pattern 菜瓜:今天听到个名词“父子容器”,百度了一下,感觉概念有点空洞,这是什么核武器? 水稻:你说的是SpringMvc和Spring吧,其实只是一个概念而已,用来将两个容器做隔离,起到解耦的作用,其中子容器可以拿到父容器的bean,父容器拿不到子容器的。但是SpringBoot出来之后这个概念基本就被淡化掉,没有太大意义,SpringBoot中只有一个容器了。 菜瓜:能不能给个demo? 水稻:可以。由于现在SpringBoot已经大行其道,Mvc你可能接触的少,甚至没接触过。
* 嵌入tomcat,由Tomcat发起对Spring容器的初始化调用过程
*
* - 启动过程
* * - Servlet规范,Servlet容器在启动之后会SPI加载META-INF/services目录下的实现类并调用其onStartup方法
* * - Spring遵循规范实现了ServletContainerInitializer接口。该接口在执行时会收集WebApplicationInitializer接口实现类并循环调用其onStartup方法
* * - 其中AbstractDispatcherServletInitializer
* * * - 将spring上下文放入ContextLoaderListener监听器,该监听会发起对refresh方法的调用
* * * - 注册dispatcherServlet,后续会由tomcat调用HttpServletBean的init方法,完成子容器的refresh调用
* *
*
* 菜瓜:嗯,效果看到了,能不能讲一下启动过程 水稻:稍等,我去下载源码。上面代码演示中已经提前说明了,父子容器的加载是Tomcat依据Servlet规范发起调用完成的 菜瓜:这样容器就可以用了吗? 水稻:是的,这样就可以直接在浏览器上面访问http://localhost:8081/hello,不过这是一个最简陋的web项目 菜瓜:懂了,最简陋是什么意思 水稻:如果我们想加一些常见的Web功能,譬如说拦截器,过滤器啥的。可以通过@EnableWebMvc注解自定义一些功能 菜瓜:我知道,这里还有个Mvc请求调用流程和这个拦截器有关。而且这个拦截器不是MethodInterceptor(切面) 水稻:没错,说到这里顺便复习一下Mvc的请求过程 菜瓜:这个之前看过不少,百度一大堆,不过还是源码亲切 总结: 【Spring】内嵌Tomcat&去Xml&调试Mvc 标签:reference efi intercept handler art demo gets 遇到 pattern 原文地址:https://www.cnblogs.com/nightOfStreet/p/13205646.html
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
*
// 此处需要取一个目录
Context context = tomcat.addContext("/", 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[]{"/"};
}
@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 {
}
}
} package com.vip.qc.mvc.controller;
import com.vip.qc.mvc.service.ServiceChild;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
/**
* @author QuCheng on 2020/6/28.
*/
@Controller
public class ControllerT implements ApplicationContextAware {
@Resource
private ServiceChild child;
@RequestMapping("/hello")
@ResponseBody
public String containter() {
child.getParent();
System.out.println("parentContainer");
return "containter";
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("子容器" + applicationContext);
System.out.println("子容器中获取父容器bean" + applicationContext.getBean(ServiceChild.class));
}
}
package com.vip.qc.mvc.service;
import com.vip.qc.mvc.controller.ControllerT;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
/**
* @author QuCheng on 2020/6/28.
*/
@Service
public class ServiceChild implements ApplicationContextAware {
// @Resource
private ControllerT controllerT;
public void getParent() {
System.out.println(controllerT);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("父容器" + applicationContext);
try {
System.out.println("父容器中获取子容器bean" + applicationContext.getBean(ControllerT.class));
} catch (NoSuchBeanDefinitionException e) {
System.out.println("找不到子容器的bean");
}
}
}
// 调用SpringWebStart的main方法启动-会有如下打印
父容器Root WebApplicationContext, started on Sun Jun 28 22:03:52 CST 2020
找不到子容器的bean
子容器WebApplicationContext for namespace ‘dispatcher-servlet‘, started on Sun Jun 28 22:03:58 CST 2020, parent: Root WebApplicationContext
子容器中获取父容器beancom.vip.qc.mvc.service.ServiceChild@4acfc43a
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//① 创建Spring父容器上下文-对象放入ContextLoadListener,后续调起完成初始化,
super.onStartup(servletContext);
//② 创建DispatcherServlet对象,后续会由tomcat调用其init方法,完成子容器的初始化工作
registerDispatcherServlet(servletContext);
}
// ①进来
protected void registerContextLoaderListener(ServletContext servletContext) {
// 此处会回调我们启动类的getRootConfigClasses()方法 - 父容器配置
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
istener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
// ②进来
protected void registerDispatcherServlet(ServletContext servletContext) {
。。。
// 此处会回调我们启动类的getServletConfigClasses()方法 - 子容器配置
WebApplicationContext servletAppContext = createServletApplicationContext();
。。。
// 初始化的dispatcherServlet,会加入Tomcat容器中-后续调用
// FrameworkServlet#initServletBean()会完成上下文初始化工作
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
。。。
}
package com.vip.qc.mvc;
import com.vip.qc.mvc.interceptor.MyInterceptor1;
import com.vip.qc.mvc.interceptor.MyInterceptor2;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* @author QuCheng on 2020/6/28.
*/
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private MyInterceptor1 interceptor1;
@Resource
private MyInterceptor2 interceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor1).addPathPatterns("/interceptor/**");
registry.addInterceptor(interceptor2).addPathPatterns("/interceptor/**");
}
}
package com.vip.qc.mvc.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author QuCheng on 2020/6/28.
*/
@Configuration
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("嘻嘻 我是拦截器1 pre");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("嘻嘻 我是拦截器1 post");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("嘻嘻 我是拦截器1 after");
}
}
package com.vip.qc.mvc.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author QuCheng on 2020/6/28.
*/
@Configuration
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("嘻嘻 我是拦截器2 pre");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("嘻嘻 我是拦截器2 post");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("嘻嘻 我是拦截器2 after");
}
}
1 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
2 。。。
3 processedRequest = checkMultipart(request);
4 multipartRequestParsed = (processedRequest != request);
5 // 1.返回一个持有methodHandler(按照URL匹配得出的被调用bean对象以及目标方法)调用链(拦截器链)对象
6 mappedHandler = getHandler(processedRequest);
7 。。。
8 // 2.按照我们现在写代码的方式,只会用到HandlerMethod,其他三种基本不会用
9 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
10 。。。
11 // 3.前置过滤器 - 顺序调用
12 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
13 return;
14 }
15 // 4.Actually invoke the handler.
16 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
17 。。。
18 applyDefaultViewName(processedRequest, mv);
19 // 5.后置过滤器 - 逆序调用
20 mappedHandler.applyPostHandle(processedRequest, response, mv);
21 。。。
22 // 6.处理试图 - 内部render
23 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
24 }
25 catch (Exception ex) {
26 // 异常处理
27 triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
28 }
29 // 异常处理
30 catch (Throwable err) {
31 triggerAfterCompletion(processedRequest, response, mappedHandler,
32 new NestedServletException("Handler processing failed", err));
33 }
34 。。。
下一篇:NCRE-Python考点
文章标题:【Spring】内嵌Tomcat&去Xml&调试Mvc
文章链接:http://soscw.com/index.php/essay/81063.html