实现SpringMVC底层机制(二)

文章目录

    • 1. 动态获取spring配置文件
        • 1.修改SunWebApplicationContext.java
        • 2.修改SunDispatcherServlet.java
    • 2.自定义Service注解
        • 1.需求分析
        • 2.编写Monster.java
        • 3.自定义Service注解
        • 4.编写Service接口MonsterService.java
        • 5.编写Service实现类MonsterServiceImpl.java
        • 6.修改SunWebApplicationContext.java的executeInstance方法,增加对Service注解的扫描
        • 7.debug测试
    • 3.完成自定义Autowired注解
        • 1.自定义Autowired注解
        • 2.在SunWebApplicationContext.java中添加方法executeAutoWired完成属性的自动装配
        • 3.修改MonsterController.java来使用Autowired注解
        • 4.单元测试
    • 4.当前阶段完成的任务
        • 自定义两个注解
        • 目前对SpringMVC容器的简单理解

1. 动态获取spring配置文件

1.修改SunWebApplicationContext.java

image-20240227174308452

2.修改SunDispatcherServlet.java

image-20240227174349197

2.自定义Service注解

1.需求分析

image-20240227174740181

2.编写Monster.java
package com.Sun.entity;/*** @author 孙显圣* @version 1.0*/
public class Monster {private Integer id;private String name;private String skill;private Integer age;public Monster(Integer id, String name, String skill, Integer age) {this.id = id;this.name = name;this.skill = skill;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Monster{" +"id=" + id +", name='" + name + '\'' +", skill='" + skill + '\'' +", age=" + age +'}';}
}
3.自定义Service注解
package com.Sun.sunspringmvc.annotation;import java.lang.annotation.*;/*** 自定义注解,用于标识一个service** @author 孙显圣* @version 1.0*/
@Target(ElementType.TYPE) //作用于目标是类
@Retention(RetentionPolicy.RUNTIME) //作用范围
@Documented
public @interface Service {String value() default "";
}
4.编写Service接口MonsterService.java
package com.Sun.sunspringmvc.annotation;import java.lang.annotation.*;/*** 自定义注解,用于标识一个service** @author 孙显圣* @version 1.0*/
@Target(ElementType.TYPE) //作用于目标是类
@Retention(RetentionPolicy.RUNTIME) //作用范围
@Documented
public @interface Service {
}
5.编写Service实现类MonsterServiceImpl.java
package com.Sun.service.Impl;import com.Sun.entity.Monster;
import com.Sun.service.MonsterService;
import com.Sun.sunspringmvc.annotation.Service;import java.util.ArrayList;
import java.util.List;/*** @author 孙显圣* @version 1.0*/
@Service
public class MonsterServiceImpl implements MonsterService {public List<Monster> listMonsters() {ArrayList<Monster> monsters = new ArrayList<Monster>();monsters.add(new Monster(1, "牛魔王", "芭蕉扇", 500));monsters.add(new Monster(2, "蜘蛛精", "吐口水", 200));return monsters;}
}
6.修改SunWebApplicationContext.java的executeInstance方法,增加对Service注解的扫描
    //编写方法,将符合要求的类反射创建对象,并封装到单例池中public void executeInstance() {//遍历所有全类名for (String classPath : classFullPathList) {try {//反射Class<?> aClass = Class.forName(classPath);//判断是否有Controller注解if (aClass.isAnnotationPresent(Controller.class)) {//有注解,当他是单例的,反射创建bean对象,放到单例池中,默认首字母小写//获取类名首字母小写String name = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);//放到单例池中singleObjects.put(name, aClass.newInstance());} else if (aClass.isAnnotationPresent(Service.class)) {//获取注解对象Service annotation = aClass.getAnnotation(Service.class);//获取注解的valueString value = annotation.value();//为了使注入的都是同一个对象,所以在这里使用反射创建实例Object bean = aClass.newInstance();//如果注解的value是空的,则使用默认机制注入到单例池中if ("".equals(value)) {//1.使用类名首字母小写来注入String simpleName = aClass.getSimpleName();String beanName = simpleName.substring(0,1).toLowerCase() + simpleName.substring(1);singleObjects.put(beanName, bean);//2.使用接口名首字母小写来注入Class<?>[] interfaces = aClass.getInterfaces();//遍历所有接口类型,进行注入for (Class<?> anInterface : interfaces) {//获取接口的名称String interfaceSimpleName = anInterface.getSimpleName();//获取首字母小写String beanName2 = interfaceSimpleName.substring(0,1).toLowerCase() + interfaceSimpleName.substring(1);//进行注入singleObjects.put(beanName2, bean);}} else {//如果value不是空的,则按照value的值进行注入singleObjects.put(value, bean);}}} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}}
7.debug测试

image-20240227192803931

3.完成自定义Autowired注解

1.自定义Autowired注解
package com.Sun.sunspringmvc.annotation;import java.lang.annotation.*;/*** @author 孙显圣* @version 1.0*/
@Target(ElementType.FIELD) //作用目标是字段
@Retention(RetentionPolicy.RUNTIME) //作用范围
@Documented
public @interface AutoWired {String value() default "";
}
2.在SunWebApplicationContext.java中添加方法executeAutoWired完成属性的自动装配

image-20240227205656667

    //编写方法,完成属性的自动装配public void executeAutoWired() throws IllegalAccessException {//首先判断容器是否为空if (singleObjects.isEmpty()) {return;}//遍历容器中的所有bean对象for (Object beanObject : singleObjects.values()) {//得到Class对象Class<?> aClass = beanObject.getClass();//得到所有字段Field[] declaredFields = aClass.getDeclaredFields();for (Field declaredField : declaredFields) {//判断这些字段是否有自动装配的注解if (declaredField.isAnnotationPresent(AutoWired.class)) {//得到这个注解的valueAutoWired annotation = declaredField.getAnnotation(AutoWired.class);String value = annotation.value();Object findBeanObject = null; //用来存储从容器中查找到的值//先判断这个注解的value有没有值if ("".equals(value)) {//如果注解没有值则按照默认的方式处理,即按照类型的首字母小写来查找String simpleName = declaredField.getType().getSimpleName();String beanName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);//从容器中查找findBeanObject = singleObjects.get(beanName);} else {//这个注解的value不是空的,则按照他的这个value在容器中查找findBeanObject = singleObjects.get(value);}if (findBeanObject == null) {throw new RuntimeException("容器中不存在你要装配的bean");} else {//进行依赖注入,需要指定给哪个对象的字段赋值//反射爆破declaredField.setAccessible(true);declaredField.set(beanObject, findBeanObject);}}}}}
3.修改MonsterController.java来使用Autowired注解

image-20240227205820110

4.单元测试

image-20240227205910924

image-20240227205928819

4.当前阶段完成的任务

自定义两个注解
  • 自定义Service注解:在原有的扫描所有文件全类名的基础上增加逻辑,判断是否具有Service注解,并根据value值或者默认方案将其注入到bean中
  • 自定义Autowired注解
    • 遍历所有单例池对象,获取对应的Class对象
    • 获取每个对象的所有字段
    • 对每个字段判断是否有Autowired注解,如果有则按照类型首字母小写或者value值来进行依赖注入
目前对SpringMVC容器的简单理解
  • tomcat启动,加载中央控制器
  • 获取spring配置文件路径,使用这个路径创建一个spring容器
  • 调用spring容器的init方法,初始化spring容器
    • 读取配置文件,得到要扫描的包,从而得到包的工作路径
    • 根据工作路径来得到包内所哟class文件的全路径
    • 遍历所有class文件的全路径,得到Class对象
    • 使用反射扫描指定注解,反射创建bean对象,放到单例池中
    • Autowired依赖注入
      • 扫描单例池,得到所有对象,从而得到Class对象
      • 使用反射得到所有字段信息,判断是否有Autowied注解,如果有则根据一定规则从单例池中查找bean对象进行依赖注入
  • 初始化映射对象列表
    • 扫描单例池,得到Class对象
    • 通过反射判断是否有RequestMapping注解,如果有则使用反射获取url和Method对象,再加上当前的对象,封装到映射对象中
    • 将这个映射对象添加到映射对象列表
  • 请求分发
    • 浏览器向中央控制器发送请求
    • 中央控制器根据请求的uri和映射对象列表的url进行比对
    • 如果匹配则反射调用Controller的方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/3738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华火电燃灶:市场认可度最高的品牌

华火电燃灶市场认可度高&#xff0c;这得益于其独特的技术优势、卓越的产品性能以及广泛的市场应用。作为一种新型的燃气灶具&#xff0c;华火电燃灶在市场上的表现备受瞩目&#xff0c;成为了众多消费者和业内人士关注的焦点。 首先&#xff0c;华火电燃灶的技术优势是其市场认…

pytorch-激活函数与GPU加速

目录 1. sigmod和tanh2. relu3. Leaky Relu4. selu5. softplus6. GPU加速7. 使用GPU加速手写数据训练 1. sigmod和tanh sigmod梯度区间是0&#xff5e;1&#xff0c;当梯度趋近0或者1时会出现梯度弥散的问题。 tanh区间时-1&#xff5e;1&#xff0c;是sigmod经过平移和缩放而…

【毕设绝技】基于 SpringCloud 的在线交易平台商城的设计与实现-数据库设计(三)

毕业设计是每个大学生的困扰&#xff0c;让毕设绝技带你走出低谷迎来希望&#xff01; 基于 SpringCloud 的在线交易平台商城的设计与实现 一、数据库设计原则 在系统中&#xff0c;数据库用来保存数据。数据库设计是整个系统的根基和起点&#xff0c;也是系统开发的重要环节…

Matlab|交直流混合配电网潮流计算(统一求解法)

目录 1 主要内容 算例模型 统一求解法迭代方程 算法流程图 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序为matlab代码&#xff0c;采用统一求解法对交直流混合配电网进行潮流计算&#xff0c;统一迭代法又称统一求解法&#xff0c;其思路是将混联系统中的交流网…

C语言 | Leetcode C语言题解之第44题通配符匹配

题目&#xff1a; 题解&#xff1a; bool allStars(char* str, int left, int right) {for (int i left; i < right; i) {if (str[i] ! *) {return false;}}return true; } bool charMatch(char u, char v) { return u v || v ?; };bool isMatch(char* s, char* p) {in…

React Hooks(常用)笔记

一、useState&#xff08;保存组件状态&#xff09; 1、基本使用 import { useState } from react;function Example() {const [initialState, setInitialState] useState(default); } useState(保存组件状态) &#xff1a;React hooks是function组件(无状态组件) &#xf…

IDEA生成测试类

方法一 具体流程: 选中要生成的测试类------------>选择code选项------------>选择Generate选项---------->选择test选项---------->选择要生成的方法 第一步: 光标选中需要生成测试类的类 找到code选项 选中Generate选项 选中test选项 选中你要生成的测试…

简单的jmeter上传文件脚本

1、设置上传接口的headers的值 2、添加post请求

数据结构系列-二叉树之前序遍历

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 这篇文章&#xff0c;我们主要的内容是对二叉树当中的前历的算法进行讲解&#xff0c;二叉树中的算法所要求实现的是 从根到左子树再到右子树的遍历顺序&#xff0c;可能这样不太…

什么是用户体验(UX)文案,为什么它很重要?

网上购物如今比以往任何时候都更加相关。所以我们将以此为例说明什么是用户体验&#xff08;UX&#xff09;文案&#xff0c;以及为什么它很重要。 假设你去了一个在线商店。你需要执行一系列操作&#xff1a; 找到合适的部分选择你感兴趣的产品弄清楚它们是什么&#xff0c;…

2.6设计模式——Flyweight 享元模式(结构型)

意图 运用共享技术有效地支持大量细粒度的对象。 结构 其中 Flyweight描述一个接口&#xff0c;通过这个接口Flyweight可以接受并作用于外部状态。ConcreteFlyweight实现Flyweight接口&#xff0c;并作为内部状态&#xff08;如果有&#xff09;增加存储空间。ConcreteFlywe…

Unity AssetsBundle打包

为什么要使用AssetsBundle包 减少安装包的大小 默认情况下&#xff0c;unity编译打包是对项目下的Assets文件夹全部内容进行压缩打包 那么按照这个原理&#xff0c;你的Assets文件夹的大小将会影响到你最终打包出的安装包的大小&#xff0c;假如你现在正在制作一个游戏项目&…

没有文件服务器,头像存哪里合适

没有文件服务器&#xff0c;头像存哪里合适 视频在bilibili&#xff1a;没有文件服务器&#xff0c;头像存哪里合适 1. 背景 之前有同学私信我说&#xff0c;他的项目只是想存个头像&#xff0c;没有别的文件存储需求&#xff0c;不想去用什么Fastdfs之类的方案搭建文件服务…

【C++杂货铺】多态

目录 &#x1f308;前言&#x1f308; &#x1f4c1;多态的概念 &#x1f4c1; 多态的定义及实现 &#x1f4c2; 多态的构成条件 &#x1f4c2; 虚函数 &#x1f4c2; 虚函数重写 &#x1f4c2; C11 override 和 final &#x1f4c2; 重载&#xff0c;覆盖&#xff08;重写…

ARM学习(26)链接库的依赖查看

笔者今天来聊一下查看链接库的依赖。 通常情况下&#xff0c;运行一个可执行文件的时候&#xff0c;可能会出现找不到依赖库的情况&#xff0c;比如图下这种情况&#xff0c;可以看到是缺少了license.dll或者libtest.so&#xff0c;所以无法运行。怎么知道它到底缺少什么dll呢&…

HarmonyOS-Next开源三方库 MPChart:打造出色的图表体验

点击下载源码https://download.csdn.net/download/liuhaikang/89228765 简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在 OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;应用开发中&#xff0c;一个强大而…

线性代数:抽象向量空间

一、说明 有些函数系列极具线性代数的向量特征。这里谈及多项式构成函数的线性代数意义。问题是这个主题能展开多少内涵&#xff1f;请看本文的论述。 二、线性空间和向量 让我先问你一个简单的问题。什么是向量&#xff1f;为了方便起见&#xff0c;二维箭头从根本上说是平…

OpenHarmony实战开发—进程间通讯

版本&#xff1a;v3.2 Beta5 进程模型 OpenHarmony的进程模型如下图所示&#xff1a; 应用中&#xff08;同一包名&#xff09;的所有UIAbility、ServiceExtensionAbility、DataShareExtensionAbility运行在同一个独立进程中&#xff0c;即图中绿色部分的“Main Process”。…

python自定义交叉熵损失,再和pytorch api对比

背景 我们知道&#xff0c;交叉熵本质上是两个概率分布之间差异的度量&#xff0c;公式如下 其中概率分布P是基准&#xff0c;我们知道H(P,Q)>0&#xff0c;那么H(P,Q)越小&#xff0c;说明Q约接近P。 损失函数本质上也是为了度量模型和完美模型的差异&#xff0c;因此可以…

网御星云防火墙策略配置

网御星云防火墙配置 1. 初始设定2. 网络配置3. 安全规则和策略4. 监控和维护零基础入门学习路线视频配套资料&国内外网安书籍、文档网络安全面试题 1. 初始设定 接入网络&#xff1a; 在开始配置之前&#xff0c;确保你的网御星云防火墙正确连接到网络。这通常涉及将WAN接…