脚本宝典收集整理的这篇文章主要介绍了热门框架系列 (二) -- SpringMvc的父子容器,SpringBoot是否有父子容器?,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
@TOC# 热门框架系列 记录在程序走的每一步___auth:huf
我们开始这个篇章吧! 在Servlet3.x,我们可以添加 Servlet Filter Listener
我们有两种方式 一种是注解的方式; @WebServlet @WebFilter @WebListener 还有一种方式 就是 :Spi
SPI 我们叫他服务接口扩展,(Service Provider Interface) 直译服务提供商接口, 不 要被这个名字唬到了, 其实很好理解的一个东西: 其实就是根据Servlet厂商(服务提供商)提供要求的一个接口, 在固定的目录 (;mETA-iNF/services)放上以接口全类名 为命名的文件, 文件中放入接口的实现的 全类名,该类由我们自己实现,按照这种约定的方式(即SPI规范),服务提供商会 调用文件中实现类的方法, 从而完成扩展。
在其规范中 我们可以看得到那么一句话:
也就是META-INF/services 路径下 放一个 javax.servlet.ServletContainerInITailizer 以下我们进入SPI 代码的实现: 准备一个maven 项目 里面三个子项目 一个Service 一个Client; 还有一个startUp 启动 我们按照上面的说法 我们在 META-INF/service 路径下放一个 接口全路径名的File 文件 文件内维护全路径类名的实现类 以下是测试结果: SPI 机制就是这样; 现在很多第三方插件使用的都是SPI机制; 当然Spring也有这样的机制; 前置知识点 到这里 就铺垫的差不多了; 如果SPI又疑问的;可以单独私聊我;Tomcat下载下来 启动会有乱码 以下是windows解决乱码的方案:
在Tomcat的config里面 LOGging.proPErties
修改:
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.encoding = GBK
<?xML version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<context:component-scan base-package="com.huf"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
我们在项目中的META-INF.services 添加 javax.servlet.ServletContainerInitializer
我们现在了解了SPI 也配置好了Tomcat 启动这一块 我暂时不细说; 后面有专门的文章来说Tomcat; 1:在我们的SPI中 我们有一个类放在META-INF下面:HufSpringServletContainerInitializer
之后 我们进入到了AbstractContextLoaderInitializer.onStartup 方法;
继承自AbstractAnnotationConfigDispatcherServletInitializer
以下是他们的继承关系
我们再AbstractDispatcherServletInitializer.onStartup方法中;我们可以发现;
这里 就准备开始创建我们的父容器; 点进去; 开始创建我们的父容器; 继续往里面看 开始注册我们的父容器; 只有register 没有refresh(); 这里我们就可以发现 这里仅仅是做了一个准备工作 容器并没有启动;最后返回一个容器;创建一个监听器;
新创建一个监听器 然后把监听器 方到Listener里面;父容器到这里就阶段性结束了;然后回到 AbstractDispatcherServletInitializer.onStartup()方法中
代码部分 我就不一句一句去解释了 这里代码非常简单;如果喜欢看我博客的同学 应该都没很大问题;这里记住 Tomcat会继续往下执行代码; 这时候会调起一个 ContextLoaderListener的contextInitialized 方法;
我们继续点进去看一下;tomcat会继续往下执行 会调起 DispatcherServlet.init 方法 这里再上一篇文章中我写有写一部分;
重点关注这个方法;
protected WebApplicationContext initWebApplicationContext() {
从域中提取出父容器;
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
设置父容器
cwac.setParent(rootContext);
}
开始初始化容器; 再上图中 进行 refresh
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
开始初始化Servlet里面的 组件
/**
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
**/
onRefresh(wac);
}
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setattribute(attrName, wac);
}
return wac;
}
这边 我们就已经把 SpringMVC的父子容器全部解释清楚了:
1:Tomcat在启动时会通过SPI注册 ContextLoaderListener和DispatcherServlet对象,同时创建父子容器 :分别创建在ContextLoaderListener初始化时创建父 容器设置配置类;在DispatcherServlet初始化时创建子容器 即2个 ApplicationContext实例设置配置类
2: Tomcat在启动时执行ContextLoaderListener和DispatcherServlet对象的初始化方 法, 执行容器refresh进行加载
3:在子容器加载时 创建SpringMVC所需的Bean和预准备的数据;
4: 子容器需要注入父容器的Bean时(比如Controller中需要@Autowired Service的Bean); 会先从子容器中找,没找到会去父容器中找: 详情见 AbstractBeanFactory#doGetBean方法
一般情况下,只有Spring和SpringMvc整合的时才会有父子容器的概念,
作用:比如我们的Controller中注入Service的时候,
发现我们依赖的是一个引用对象,
那么他就 会调用getBean去把service找出来;
但是当前所在的容器是web子容器,
那么就会在这里的 先去父容器找
回到我们 文章当中的那个问题:
父子容器的定义: 1.早期Spring为了划分框架边界。service、DAO层我们一般使用spring框架来管理、controller 层交给springmvc管理; 2.规范整体架构 使 父容器service无法访问子容器controller、子容器 controller可以访问父容器 service、 3.方便子容器的切换。如果现在我们想把web层从spring mvc替换成struts, 那么只需要将springmvc.xml替换成Struts的配置文件struts.xml即可,而 springcore.xml不需要改变
以上是脚本宝典为你收集整理的热门框架系列 (二) -- SpringMvc的父子容器,SpringBoot是否有父子容器?全部内容,希望文章能够帮你解决热门框架系列 (二) -- SpringMvc的父子容器,SpringBoot是否有父子容器?所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。