范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

SpringMVC的父子容器你都了解了吗?

  环境:Spring5.3.23配置文件
  如果我们不使用基于注解的方式,那么在Spring Web项目一般我们都会在web.xml文件中做如下的配置:
  web.xml            org.springframework.web.context.ContextLoaderListener              contextConfigLocation      /WEB-INF/app-context.xml              app      org.springframework.web.servlet.DispatcherServlet              contextConfigLocation                    1              app      /app/*      父容器初始化
  通过在web.xml中还会配置一个监听器,而这个监听器的作用就是初始化父容器的     org.springframework.web.context.ContextLoaderListener  
  上面配置的监听程序是用来初始化父容器。  public class ContextLoader {    private WebApplicationContext context;    private static final Properties defaultStrategies;    public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";    static {      try {        private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";        // 从类路径下查找ContextLoader.properties文件        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);        // 加载配置文件;默认情况下会从spring-web-xxx.jar包下的org.springframework.web.context包下有该文件        // 文件内容:org.springframework.web.context.WebApplicationContext=        // org.springframework.web.context.support.XmlWebApplicationContext        // 也就是默认情况下实例化的是XmlWebApplicationContext容器对象        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);      }    }    protected WebApplicationContext createWebApplicationContext(ServletContext sc) {      // 获取容器ApplicationContext具体的类的Class对象      Class<?> contextClass = determineContextClass(sc);      // 实例化XmlWebApplicationContext对象,该对象就是基于xml的配置的解析类      return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);    }    protected Class<?> determineContextClass(ServletContext servletContext) {      public static final String CONTEXT_CLASS_PARAM = "contextClass";      // 获取在web.xml中配置的context-param参数名称为contextClass;这里其实就是配置你要使用哪个ApplicationContext容器对象      String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);      // 如果配置了使用你配置的ApplicationContext容器的具体对象      if (contextClassName != null) {        try {          return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());        }      } else {        // 如果没有在web.xml配置文件中配置contextClass参数,则通过下面的方式获取        // 这里获取的就是上面static代码段中加载的配置        contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());        try {          return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());        }      }    }    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac,ServletContext sc) {      wac.setServletContext(sc);      // 获取在web.xml中配置的上下文参数(context-param), 名称为contextConfigLocation的参数值      String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);      if (configLocationParam != null) {        // 如果配置了设置配置文件路径        wac.setConfigLocation(configLocationParam);      }      // 执行刷新,也就是解析处理上面配置的spring配置文件      // 如果没有配置上面的contextConfigLocation参数,那么会读取默认的applicationContext.xml配置文件      // 查看XmlWebApplicationContext类      wac.refresh();    }  }  public class ContextLoaderListener extends ContextLoader implements ServletContextListener {    public void contextInitialized(ServletContextEvent event) {      initWebApplicationContext(event.getServletContext());    }    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {      try {        if (this.context == null) {          // 创建容器,在父类中创建出XmlWebApplicationContext对象          this.context = createWebApplicationContext(servletContext);        }        // mlWebApplicationContext实现了ConfigurableWebApplicationContext接口        if (this.context instanceof ConfigurableWebApplicationContext) {          ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;          // 确定此应用程序上下文是否处于活动状态,即它是否已刷新至少一次且尚未关闭。          if (!cwac.isActive()) {            // ...            // 刷新上下文            configureAndRefreshWebApplicationContext(cwac, servletContext);          }        }        // 将实例化的ApplicationContext保存到ServletContext对象中        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);          ClassLoader ccl = Thread.currentThread().getContextClassLoader();        if (ccl == ContextLoader.class.getClassLoader()) {          currentContext = this.context;        }        else if (ccl != null) {          currentContextPerThread.put(ccl, this.context);        }        return this.context;      }    }  }  public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";        protected String[] getDefaultConfigLocations() {      if (getNamespace() != null) {        return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};      } else {        return new String[] {DEFAULT_CONFIG_LOCATION};      }    }    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {      loadBeanDefinitions(beanDefinitionReader);    }    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {      // 调用父类AbstractRefreshableWebApplicationContext方法      String[] configLocations = getConfigLocations();      if (configLocations != null) {        for (String configLocation : configLocations) {          reader.loadBeanDefinitions(configLocation);        }      }    }  }  // XmlWebApplicationContext在执行refresh的时候有这么一步  public abstract class AbstractApplicationContext extends DefaultResourceLoader      implements ConfigurableApplicationContext {    public void refresh() {      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();    }    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {      refreshBeanFactory();      return getBeanFactory();    }  }  public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext      implements ConfigurableWebApplicationContext, ThemeSource {    public String[] getConfigLocations() {      return super.getConfigLocations();    }  }  public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext      implements BeanNameAware, InitializingBean {    protected String[] getConfigLocations() {      // 如果没有配置,则调用默认的方法调用子类XmlWebApplicationContext重写的方法      return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());    }  }  public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {    protected final void refreshBeanFactory() throws BeansException {      // 调用子类XmlWebApplicationContext重写的方法      loadBeanDefinitions(beanFactory);    }  }
  总结: 从配置文件中获取contextClass参数
  如果没有则读取spring-web-xxx.jar中org.springframework.web.context包下的ContextLoader.properties文件
  目的就是容器实例化具体 ApplicationContext 那个子类对象。
  刷新初始化ApplicationContext对象
  这里具体的类是 XmlWebApplicationContext 对象。
  1. 首先是设置要读取的配置文件
  读取web.xml中配置的  参数contextConfigLocation,如果没有设置该 参数,则使用默认的/WEB-INF/applicationContext.xml 。
  2. 调用refresh初始化spring容器
  保存spring容器对象
  实例化后会将该容器对象保存到 ServletContext 中,以 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 为name存入。
  子容器初始化
  子容器的初始化就是 DispatcherServlet  配置的  参数 public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {    public final void init() throws ServletException {        // 这里代码的作用就是用来读取DispatcherServlet配置的contextConfigLocation参数,然后设置到      // FrameworkServlet中的contextConfigLocation属性中      // 这里就是通过BeanWrapper来完成此操作      PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);      if (!pvs.isEmpty()) {        try {          BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);          ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());          bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));          initBeanWrapper(bw);          bw.setPropertyValues(pvs, true);        }      }      // 到这里就设置完了配置在DispatcherServlet中的contextConfigLocation参数            // 初始化Servlet Bean      initServletBean();    }  }
  FrameworkServlet   public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {    public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;    public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";    // 该值在父类的init方法中已经通过BeanWrapper设置搞定了,当如如果没有配置会有默认机制的,下面会看到    private String contextConfigLocation;    protected final void initServletBean() throws ServletException {      this.webApplicationContext = initWebApplicationContext();    }    protected WebApplicationContext initWebApplicationContext() {      // 从ServletContext中读取在上面(初始化父容器)设置的WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE      // 容器对象      WebApplicationContext rootContext =          WebApplicationContextUtils.getWebApplicationContext(getServletContext());      WebApplicationContext wac = null;      // ...      if (wac == null) {        // 查找容器        // 这里默认还是返回null,这里就是看你在配置DispatcherServlet的时候有没有配置contextAttribute属性        // 如果你设置了该属性,会从ServletContext中读取配置的contextAttribute属性对应的值(该值必须是WebApplicationContext)        // 如果不是则抛出异常        wac = findWebApplicationContext();      }      if (wac == null) {        // 到这还没有容器对象,则创建容器对象,同时这里的rootContext会作为父容器        wac = createWebApplicationContext(rootContext);      }      return wac;    }    protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {      return createWebApplicationContext((ApplicationContext) parent);    }    protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {      // 这里就是获取要实例化的默认ApplictionContext对象,XmlWebApplicationContext      Class<?> contextClass = getContextClass();      // 实例化      ConfigurableWebApplicationContext wac =          (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);      wac.setEnvironment(getEnvironment());      // 设置父容器      wac.setParent(parent);      // 获取要读取加载的配置文件,如果你没有则就是null      String configLocation = getContextConfigLocation();      // 如果你没有配置,不进入      if (configLocation != null) {        wac.setConfigLocation(configLocation);      }      // 刷新上下文      configureAndRefreshWebApplicationContext(wac);        return wac;    }    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {      wac.setServletContext(getServletContext());      wac.setServletConfig(getServletConfig());      // 这里就非常关键了,记住你这里有了namespace的值      wac.setNamespace(getNamespace());      wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));        ConfigurableEnvironment env = wac.getEnvironment();      if (env instanceof ConfigurableWebEnvironment) {        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());      }        postProcessWebApplicationContext(wac);      applyInitializers(wac);      // 这里refresh的过程就和上面初始化父容器的流程一样了,会查找使用的那些xml配置文件      wac.refresh();    }    public String getNamespace() {      // 根据你配置的xxx名称拼接      // 默认就返回:xxx-servlet(xxx就是你配置的servlet名称)      return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);    }    public String getContextConfigLocation() {      return this.contextConfigLocation;    }  }  // 如果你没有配置contextConfigLocation,那么就找默认的配置xml文件  public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";        protected String[] getDefaultConfigLocations() {      // 上面看到了我们的getNamespace设置了值,则进入      if (getNamespace() != null) {        // 这里就拼接成:/WEB-INF/xxx-servlet.xml(也就是,如果你没有为DispatcherServlet配置contextConfigLocation属性)        return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};      } else {        return new String[] {DEFAULT_CONFIG_LOCATION};      }    }  }
  总结: 读取Servlet配置参数
  读取配置 DispatcherServlet  时配置的参数,通过 BeanWrapper  设置当前Servlet对应的属性中。
  实例化Spring容器对象
  1. 实例化Spring容器对象
  2. 设置容器对象的配置文件
  如果你为Servlet配置了contextConfigLocation,则使用该参数对应的值作为子容器解 析的xml配置文件
  3. 设置名称空间namespace
  根据你配置的servlet名称 + "-servlet"作为名称空间
  刷新Spring容器
  调用refresh方法;如果你没有配置contextConfigLocation,则会查找默认的配置文件,而这个默认配置在 XmlWebApplicationContext  已经重写了,会判断当前的namespace是否为空,不为空则返回 /WEB-INF/xxx-servlet.xml  (xxx: 取值根据你配置的servlet-name)。
  完毕!!!
  SpringBoot对Spring MVC都做了哪些事?(一)
  SpringBoot对Spring MVC都做了哪些事?(二)
  SpringBoot对Spring MVC都做了哪些事?(三)
  SpringBoot对Spring MVC都做了哪些事?(四)
  Spring中的@Configuration注解你真的了解吗?
  Spring MVC 异常处理方式
  Spring中字段格式化的使用详解
  Spring MVC 异步请求方式
  Spring容器这些扩展点你都清楚了吗?
  Spring 自定义Advisor以编程的方式实现AOP
  SpringBoot WebFlux整合Spring Security进行权限认证
  SpringBoot项目中应用Spring Batch批处理框架,处理大数据新方案
  Spring Security权限控制系列(七)

61岁周华健长居美国!与女儿女婿在小饭馆用餐,身材壮硕满脸通红饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!9月13日,一组周华健现身美国小饭馆的照片,引起网友持续热议。原来,近日有一名女粉丝在餐厅吃饭时,意外碰到了周华健,对方欧冠杯前瞻比尔森vs国际米兰,状态火热!B罗联赛献绝杀比赛分析比尔森胜利目前在捷甲积分榜排名第2,上轮联赛客场3比2击败了奥洛穆茨,近期连续6场比赛都能取得进球,一共打进11球,进攻很稳定。比尔森胜利上场联赛进行了一定的轮换调整,其中欧冠比尔森VS国际米兰,蓝黑军团重拳出击?周二001欧冠比尔森VS国际米兰202209140045皮尔森目前在捷甲联赛排行第5名。本赛季皮尔森的表现出色,目前联赛6轮比赛下来,在联赛争冠位置。而且攻防端表现合格,目前总进球36氪首发鲨湾科技获千万美元级A轮融资,国际电动摩托车品牌的科技探索文高雅编辑彭孝秋36氪获悉,国际化中高端智能电动摩托车企业鲨湾科技已于近日完成千万美元级A轮融资,本轮融资由MaisonCapital领投,融资资金将用于扩充研发团队工厂产能,加快国际乒联更新排名樊振东孙颖莎继续排名世界第一来源中国新闻网中新网9月13日电日前,国际乒联官方网站更新了2022年第37周世界排名。在男单方面,樊振东马龙梁靖崑继续排名前三位,王楚钦林高远分列第1112位。女单方面,孙颖莎陈射频芯片龙头企业,卓胜微全面开花,对标国际大厂的进阶之路(报告出品方分析师平安证券付强徐勇)一国内射频芯片龙头,全面布局射频前端业务1。1电视芯片起家,转型后专注射频前端芯片领域厚积薄发,搭上智能手机赛道一举成为国内射频芯片龙头企业。公推荐10款Steam本月特惠游戏,方舟生存进化水晶岛DLC环境极美SnaiGameUSA是一家知名的开发商,它所发行的一些游戏作品在玩家之间的口碑非常的好,在Steam也是广受玩家热爱的存在。现在,SnaiGameUSA的游戏正在Steam特卖,第四届全球新能源与智能汽车供应链创新大会圆满落幕在汽车产业百年未有之大变革疫情国际政经新形势等多重因素推动下,全球汽车产业链供应链正加速重构。要发挥集中力量办大事的制度优势,突破关键核心技术,打造自主可控的核心供应链,已成为行业秋季补好碱,牛皮癣少复发牛皮癣是不是总是治不好?可能是血液出现了问题。根据上万份检查单发现,牛皮癣的血液是偏酸性的,而正常人的血液是呈弱碱性的。所以想要牛皮癣治好不复发,调节血液酸碱很重要。碱性食物对于牛这是我见过最减龄时髦的秋季搭法,鲨鱼裤球鞋,显瘦显年轻头条创作挑战赛到了秋天,时髦精们可以选择的穿搭方式很多,有些搭法能够轻松展现穿搭者优雅温柔的气质,有些搭法帅气不羁。不过要提到最减龄时髦的穿搭方式,还要数鲨鱼裤球鞋。这一穿法是很多能让女人穿出优雅气质的秋季搭法,除了风衣踝靴,还有这些对于大多数人来说,穿衣打扮最大诉求其实是穿出优雅气质,穿衣输在气质上,再怎么抢眼时髦都没用。特别对于一些成熟女人,穿风衣简约得体最重要。那么到了秋天,有哪些风衣搭配值得大家尝试呢?
腌腊肉时,不要直接抹盐,做好这2步,不发霉不变臭,越放越香秋风起,吃腊味。又到腊肉飘香时,每年寒风起,天高气爽,都是晒腊肉的好季节,挂满腊肉的阳台农院,充满了生活的气息。很多人都会喜欢自己晒一些腊肉腊肠腊鱼,把鲜肉做成腊肉,不仅能长时间保冻鸡腿都从哪来的,为何那么便宜?能经常吃吗?现在有了答案现在很多消费者都喜欢购买超市里的冻鸡腿,因为冻鸡腿价格便宜又好吃,拿回家里油炸或红烧,会很受家人的喜爱。不过,也有细心的消费者提出,超市或菜场售卖的这些冻鸡腿为什么这么便宜?冻鸡腿全国哪里的酱油最好吃?经过评比,这7款最为出名,有你家乡吗?导读酱油是我们日常中最常使用的调味品之一,早在三千多年前,中国周朝就有制作酱的记载了,当时,酱油还是中国古代皇帝御用的调味品。而最早的酱油是由鲜肉腌制而成,和鱼露的做法很接近,而随哪些补水美白爽肤水好用?高人气爽肤水推荐用后肌肤水嫩光滑哪些补水美白爽肤水好用?高人气爽肤水推荐用后肌肤水嫩光滑!泰国VC水主要功效美白提亮保湿缩小毛孔等。推荐理由vc水就是去年被炒热的,我年底买了一瓶,毕竟也便宜。几十块钱一大瓶感觉很我妈去世后的第七天,家族宴会上,我爸带回来一个私生女我妈去世后的第七天,家族宴会上,我爸带回来一个私生女。她穿着朱红色的抹胸小礼服,踩着双不太合脚的高跟鞋,努力昂着头,落落大方地说叔伯婶婶们,晚上好,我是宋明喜。在我妈头七这天,宋明我又被李沁圈粉了,黑色上衣叉裙,优雅知性我又被李沁圈粉了,西装上衣搭配下身开叉裙,知性且优雅。黑色上衣开叉裙李沁遴选的这件西装添加了垫肩的设计,不仅修饰身形弱化骨架,还能穿出英姿飒爽的气场感。搭配富有开叉设计的西装套裙,乔布斯小女儿超模脸真高级!穿马甲裙为LV高调拍广告,身材超性感乔布斯今年24岁的小女儿伊芙可以说是人生大赢家,不仅出身优越,拥有着别人享受不到的资源,自己也是非常优秀的学霸,从小学习马术,还获得过全球1000名25岁以下最佳马术运动员排名第五不想头发变成蒲公英?这3个方法可以试试很多人都想要一头乌黑靓丽的秀发,尤其是产后的妈妈。因为许多妇女发现她们的头发在分娩后开始脱落,甚至随处飘落,成为名副其实的蒲公英。但其实在全国4亿脱发人口中,女性也是占了一部分的。男篮吹集结号首发控卫打石膏去集训杜锋急招辽宁男篮成员入队10月30日CBA第一阶段比赛结束后,入选新一届国家队的成员急急忙忙从杭州赶赴集训地广州,首发控卫孙铭徽甚至打着石膏也得去,真没办法啊,一共17人,到出发时已经有四人受伤了,连15滋阴润肺,能缓解气管炎的肺心草有哪些功效与作用?肺心草具有很高的药用价值,既能清热润肺,又能消肿止痛,且含有天然解毒成分,对人体有很多益处,今天就带大家了解一下肺心草的功效和作用。一滋阴润肺肺心草性微寒,能有效缓解肺热肺燥,对于看中医需要喝中药吗你觉得现在看中医还需要熬中药汤喝吗夫人禀五常,因风气而生长,风气虽能生万物,亦能害万物,如水能浮舟,亦能覆舟。中国传统医药理论指导采集炮制制剂,说明作用机理,指导临床应用的药物,统