当前位置: 首页 > news >正文

Spring MVC 四:Context层级

这一节我们来回答上篇文章中避而不谈的有关什么是RootApplicationContext的问题。

这就需要引入Spring MVC的有关Context Hierarchy的问题。Context Hierarchy意思就是Context层级,既然说到Context层级,说明在Spring MVC项目中,可能存在不止一个Context。

Context是上下文的意思,我们可以直接理解为容器,上一篇文章我们提到了ServletApplicationContext的概念,可以理解为Servlet容器。

除此之外,Spring项目中肯定还有有IoC容器,我们今天就来聊一下这两个容器之间的关系。

为什么需要容器

我们可以这样理解:凡是具有生命周期的对象,也就是说对象并不是在当前现成创建、使用完成之后就销毁的,而是在当前现成使用完成之后不销毁、其他线程还需要继续使用的。这中对象就需要一个容器来保存。

比如Spring的单例Bean,在Spring初始化的过程中就会创建并存入Ioc容器,之后应用使用过程中从Ioc容器中获取。

Servlet对象(比如DispatchServlet)也是这样,在Web应用初始化的过程中创建,Controller、ViewResolver、ExceptionHandler等对象随之也完成创建,这些对象在整个应用的生命周期中会反复使用,因此,Servlet也必须要有一个容器来存储。

Spring把容器称之为上下文,Context。

我们可以把Servlet容器叫做WebApplicationContext,因为Servlet的出现就是为了解决Web应用的,所以自然而然的,我们可以把Servlet容器称为WebApplicationContext。

相对应的,Spring Ioc容器,我们可以称之为RootApplicationContext:根容器。

Servlet和根容器的关系

下图一目了然的说明了两者之间的关系:
在这里插入图片描述

Servlet容器存放Controller、VIewResolver、HanderMapping等DispatcherServlet的相关对象,根容器可以存放其他Service、Repositories等对象。

一个DispatcherServlet可以对应的有一个Servlet容器,一个Web应用可以有多个DispatcherServlet(这种应用其实比较少见),所以一个应用可以有多个Servlet容器。但是一般情况下,即使有多个Servlet容器,一个应用也希望只有一个根容器,以便在不同的Servlet容器之间共享根容器的对象。

举例

我们下面用几个例子来说明两者之间的关系。

还是延用上一篇文章的例子,并做如下简单的改造。

首先,增加一个单例bean,以便启用Spring IoC容器。我们只是简单引入IoC容器,单例bean不需要太复杂,

package org.example.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;@Component
public class UserService {@AutowiredApplicationContext app;public String getUserInfo(){System.out.println(" application in UserService:"+ app);return "This is userinfo...from UserService...";}
}

只有一个方法,返回String。不过为了能说明当前单例Bean所处的容器,我们通过@Autowired引入ApplicationContext对象(希望大家还记得这一点,我们前面讲过通过什么样的方式,能够在应用中拿到Bean所处的Application对象),这样的话我们就能够知道当前Spring应用的Ioc容器具体是哪个对象。

其次,我们需要新增一个Spring Ioc容器的配置类,我们称之为RootConfiguration,配置类仅指定扫描路径即可:

import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan("org.example.service")
public class RootConfiguration {
}

最后,Controller改造一下,与UserService一样,引入ApplicationContext(Controller中的ApplicationContext,我们可以人为他就是Servlet容器),log打印一下具体的Context,同时我们打印一下当前Servlet容器的父容器:

package org.example.controller;import org.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;@Controller
public class HelloWorldController {@AutowiredUserService userService;@AutowiredApplicationContext app;@GetMapping("/hello")@ResponseBodypublic String hello(ModelAndView model){DispatcherServlet d;String userInfo = userService.getUserInfo();System.out.println("app in controller:"+app);System.out.println("servletContext's parent Context"+app.getParent());return "<h1>"+userInfo+"</h1>";}
}

OK,准备工作完成,开始验证。

举例1 根容器不是必须存在

首先,根容器不是必须存在的。

但是由于我们增加了UserService这个bean,所以必须有Ioc容器,我们必须为IoC容器指定配置文件的包扫描路径。

既然我们说根容器不是必须存在,那么,意思就是说,Servlet容器要同时充当IoC容器的角色。

所以我们必须在MvcConfiguration中增加宝扫描路径:

package org.example.configuration;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan({"org.example.service","org.example.controller"})
//@ComponentScan({"org.example.controller"})
public class MvcConfiguration {
}

MvcInitializer中的getRootConfigClasses()返回null,则应用初始化的过程中就不会创建根容器(通过查看createRootApplicationContext方法源码得出的结论):

public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getRootConfigClasses() {return null;}

启动应用,测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBftrdeQ-1693234193599)(/img/bVc9m07)]
说明应用是可以正常运行的,后台log:

 application in UserService:WebApplicationContext for namespace 'dispatcher-servlet', started on Tue Aug 22 22:35:34 CST 2023
app in controller:WebApplicationContext for namespace 'dispatcher-servlet', started on Tue Aug 22 22:35:34 CST 2023
servletContext's parent Contextnull

后台log说明,Servlet容器和Spring IoC容器是同一个,他们的父容器是null。

指定Ioc容器为父容器

首先修改MvcConfiguration,指定Servlet容器只扫描Controller包:

package org.example.configuration;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan({"org.example.controller"})
public class MvcConfiguration {
}

MvcInitializer中的getRootConfigClasses()返回我们新增的RootConfiguration,则应用初始化的过程中就会创建根容器:

public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[] {RootConfiguration.class};}

启动应用,测试:

 application in UserService:Root WebApplicationContext, started on Tue Aug 22 22:44:08 CST 2023
app in controller:WebApplicationContext for namespace 'dispatcher-servlet', started on Tue Aug 22 22:44:09 CST 2023, parent: Root WebApplicationContext
servletContext's parent ContextRoot WebApplicationContext, started on Tue Aug 22 22:44:08 CST 2023

有测试结果可知:
1. UserService所处的是根容器。
2. Controller所处的是Servlet容器。
3. Servlet容器的父容器是根容器。

测试结果验证了我们前面的推论,而且,Spring底层自动将Servlet容器的父容器设置为了根容器!在什么地方设置的?

Spring MVC框架在DispatcherServlet的初始化过程中(init方法),initWebApplicationContext的时候设置ServletContext的父容器为根容器。

上一篇 Spring MVC 三 :基于注解配置

相关文章:

Spring MVC 四:Context层级

这一节我们来回答上篇文章中避而不谈的有关什么是RootApplicationContext的问题。 这就需要引入Spring MVC的有关Context Hierarchy的问题。Context Hierarchy意思就是Context层级&#xff0c;既然说到Context层级&#xff0c;说明在Spring MVC项目中&#xff0c;可能存在不止…...

【C++ 学习 ⑱】- 多态(上)

目录 一、多态的概念和虚函数 1.1 - 用基类指针指向派生类对象 1.2 - 虚函数和虚函数的重写 1.3 - 多态构成的条件 1.4 - 多态的应用场景 二、协变和如何析构派生类对象 2.1 - 协变 2.2 - 如何析构派生类对象 三、C11 的 override 和 final 关键字 一、多态的概念和虚…...

合宙Air724UG LuatOS-Air LVGL API控件--进度条 (Bar)

进度条 (Bar) Bar 是进度条&#xff0c;可以用来显示数值&#xff0c;加载进度。 示例代码 – 创建进度条 bar lvgl.bar_create(lvgl.scr_act(), nil) – 设置尺寸 lvgl.obj_set_size(bar, 200, 20); – 设置位置居中 lvgl.obj_align(bar, NULL, lvgl.ALIGN_CENTER, 0, 0) …...

图神经网络与分子表征:番外——基组选择

学过高斯软件的人都知道&#xff0c;我们在撰写输入文件 gjf 时需要准备输入【泛函】和【基组】这两个关键词。 【泛函】敲定计算方法&#xff0c;【基组】则类似格点积分中的密度&#xff0c;与计算精度密切相关。 部分研究人员借用高斯中的一系列基组去包装输入几何信息&am…...

rabbitmq笔记-rabbitmq客户端开发使用

连接RabbitMQ 1.创建ConnectionFactory&#xff0c;给定参数ip地址&#xff0c;端口号&#xff0c;用户名和密码等 2.创建ConnectionFactory&#xff0c;使用uri方式实现&#xff0c;创建channel。 注意&#xff1a; Connection可以用来创建多个channel实例&#xff0c;但c…...

13.Oracle中nvl()与nvl2()函数详解

Oracle中nvl()与nvl2()函数详解&#xff1a; 函数nvl(expression1,expression2)根据参数1是否为null返回参数1或参数2的值&#xff1b; 函数nvl2(expression1,expression2,expression3)根据参数1是否为null返回参数2或参数3的值 1.nvl&#xff1a;根据参数1是否为null返回参数…...

设置某行被选中并滚动到改行

<el-table :data"tableDamItem" ref"singleTable" stripe style"width: 100%" height"250" highlight-current-row v-on:row-click"handleTableRow"></el-table>/*** 设置表格行被选中,并滚动到该行* param po…...

React钩子函数之useRef的基本使用

React钩子函数中的useRef是一个非常有用的工具&#xff0c;它可以用来获取DOM元素或者保存一些变量。在这篇文章中&#xff0c;我们将会讨论useRef的基本使用。 首先&#xff0c;我们需要知道useRef是如何工作的。它返回一个可变的ref对象&#xff0c;这个对象可以在组件的整个…...

无风扇迷你电脑信息与购买指南

本文将解释什么是无风扇迷你电脑&#xff0c;以及计算产品组合中你可以购买的一些不同的无风扇迷你电脑的信息指南。 无风扇迷你电脑是一种小型工业计算机&#xff0c;旨在处理复杂的工业工作负载。迷你电脑是通过散热器被动冷却可在各种类型的易失性环境中部署。无风扇微型计…...

比特币是怎么回事?

比特币是怎么回事&#xff1f; 一句话描述就是&#xff0c;初始化几个比特币&#xff0c;申请成为矿工组织&#xff0c;发生交易时抢单记账成功可以比特币奖励&#xff0c;随着比特币数量的增加&#xff0c;奖励越来越少。怎么记账成功呢&#xff0c;通过交易信息幸运数字哈希…...

vue3+ts+uniapp小程序端自定义日期选择器基于内置组件picker-view + 扩展组件 Popup 实现自定义日期选择及其他选择

vue3ts 基于内置组件picker-view 扩展组件 Popup 实现自定义日期选择及其他选择 vue3tsuniapp小程序端自定义日期选择器 1.先上效果图2.代码展示2.1 组件2.2 公共方法处理日期2.3 使用组件 3.注意事项3.1refSelectDialog3.1 backgroundColor"#fff" 圆角问题 自我记…...

Java进阶篇--泛型

前言 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。它允许在定义类、接口和方法时使用类型参数。这种技术使得在编译期间可以使用任何类型&#xff0c;而…...

android framework之Applicataion启动流程分析

Application启动流程分析 启动方式一&#xff1a;通过Launcher启动app 启动方式二&#xff1a;在某一个app里启动第二个app的Activity. 以上两种方式均可触发app进程的启动。但无论哪种方式&#xff0c;最终通过通过调用AMS的startActivity()来启动application的。 根据上图…...

Linux Day10 ---Mybash

目录 一、Mybash介绍 1.1.mybash.c 打印函数 分割函数 命令函数 二、Mybash实现 2.1.打印函数 2.1.1需要使用到的功能函数 1.获取与当前用户关联的UID 2.获取与当前用户的相关信息---一个结构体&#xff08;passwd&#xff09; 3.获取主机信息 4.获取当前所处位置 5.给…...

Flask-Sockets和Flask-Login联合实现websocket的登录认证功能

flask_login 提供了一个方便的方式来管理用户会话。当你在 Flask 的 HTTP 视图中使用它时&#xff0c;你可以简单地使用 login_required 装饰器来确保用户已登录。 但是&#xff0c;flask_sockets 并没有直接与 flask_login 集成。如果你想在建立 WebSocket 连接时检查用户是否…...

东盟全面覆盖?长城战略部署核心区域市场,首个百万粉丝国产品牌

根据最新消息&#xff0c;长城汽车在东南亚地区取得了巨大的成功&#xff0c;成功进军了亚洲最大的汽车市场之一-印度尼西亚。这标志着长城汽车已经实现了东盟核心市场的全面覆盖&#xff0c;成为全球布局的重要一步。 在过去的几年里&#xff0c;长城汽车在东盟地区的市场布局…...

基于PHP的电脑商城系统

有需要请加文章底部Q哦 可远程调试 基于PHP的电脑商城系统 一 介绍 此电脑商城系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。用户可注册登录&#xff0c;购物下单&#xff0c;评论等。管理员登录后台对电脑商品&#xff0c;用户&#xff0c;订单&a…...

无客户端网络准入方案,为集成电路企业终端管理开启省事更省心模式

宁盾无客户端网络准入控制方案正在成为先进制造、高科技互联网企业等创新型客户的优选方案。创新型客户以技术密集型、研发人员占比高著称&#xff0c;在进行网络准入建设时&#xff0c;如何平衡好用户体验与顺利达成项目预期之间的矛盾&#xff0c;是创新企业 IT 安全团队格外…...

5G与4G的RRC协议之异同

什么是无线资源控制&#xff08;RRC&#xff09;&#xff1f; 我们知道&#xff0c;在移动通信中&#xff0c;无线资源管理是非常重要的一个环节&#xff0c;首先介绍一下什么是无线资源控制&#xff08;RRC&#xff09;。 手机和网络通过无线信道相互通信&#xff0c;彼此交…...

横扫“盲区”、“看透”缺陷,维视智造推出短波红外相机

在可见光领域&#xff0c;工业相机的视觉应用已经十分成熟&#xff0c;但在日常的客户咨询中&#xff0c;我们也经常接到一些“超纲需求”——客户想要检测“白底上的白色缺陷”、“不透明包装内的透明物体有无”等&#xff0c;均属于可见光无法实现的检测&#xff0c;而市面上…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...