实现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.hqwc.cn/news/651285.html

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

相关文章

linux系统下载huggingface大模型教程

文章目录 准备工作添加SSH Key生成Access Token 模型下载公开模型下载&#xff08;bert-base-chinese为例&#xff09;非公开模型下载&#xff08;Llama3为例&#xff09;权限申请官网预训练模型下载huggingface仓库下载 准备工作 添加SSH Key # 本地机器生成ssh key # step1…

JavaScript-3(内置对象+数组对象+字符串对象)

目录 1.预解析 2.对象 什么是对象 创建对象的三种方法 利用字面量创建方法 利用new Object创建对象 构造函数创建对象 new关键字 遍历对象 3.内置对象 Math对象 Math概述 Math随机数 Date日期对象 格式化日期 Date总的时间毫秒 4.数组对象 创建数组的两种方式…

OpenHarmony实战开发-按钮 (Button)

Button是按钮组件&#xff0c;通常用于响应用户的点击操作&#xff0c;其类型包括胶囊按钮、圆形按钮、普通按钮。Button做为容器使用时可以通过添加子组件实现包含文字、图片等元素的按钮。具体用法请参考Button。 创建按钮 Button通过调用接口来创建&#xff0c;接口调用有…

JetBrains CLion v2023.3.4 激活版 (C/C++ 集成开发IDE)

前言 JetBrains CLion是一款跨平台的C/C集成开发环境&#xff0c;由JetBrains公司推出。其最新版本支持C14几乎完全&#xff0c;并初步支持C17&#xff0c;使得编写代码更加便捷。CLion还提供了Disassembly view&#xff08;反汇编视图&#xff09;&#xff0c;即使没有源代码…

C++对象的初始化和处理

生活中我们买的电子产品都基本会有出厂设置!在某一天我们不用时候也会删除一些自己信息数据保证安全。 C中的面向对象来源于生活&#xff0c;每个对象也都会有初始设置以及对象销毁前的清理数据的设置。 构造函数和析构函数 对象的初始化和清理也是两个非常重要的安全问题 一…

CSS中设置透明度的2个属性:opacity,RGBA以及它们的区别

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合…

什么是停车场车牌识别系统,停车场车牌识别系统工作原理是什么

在现代城市中&#xff0c;随着机动车辆数量的急剧增加&#xff0c;停车场道闸系统的智能化管理变得尤为重要。传统的人工管理方式不仅效率低下&#xff0c;而且容易出错&#xff0c;无法满足日益增长的车辆管理需求。车牌识别技术的引入&#xff0c;为停车场道闸系统带来了革命…

python 编程小技巧:# type: 类型注释语法

# type: 是 Python 3.5 引入的一种类型注释语法&#xff0c;用于在代码中指定变量、函数、方法等对象的类型信息&#xff0c;以便 IDE 和类型检查工具等工具能够更好地理解和分析代码。具体来说&#xff0c;# type: 后面可以跟一个类型注释&#xff0c;用于指定对象的类型&…

小程序变更主体还要重新备案吗?

小程序迁移变更主体有什么作用&#xff1f;小程序迁移变更主体的作用可不止变更主体这一个哦&#xff01;还可以解决一些历史遗留问题&#xff0c;比如小程序申请时主体不准确&#xff0c;或者主体发生合并、分立或业务调整等情况。这样一来&#xff0c;账号在认证或年审时就不…

42-巩固练习(二)

42-1 函数的递归 1、问&#xff1a;关于递归的描述错误的是&#xff08;&#xff09; A.存在限制条件&#xff0c;当满足这个限制条件的时候。递归便不再维续 B.每次递归调用之后越来越接近这个限制条件 C.递归可以无限递归下去 D.递归层次太深&#xff0c;会出现栈溢出现…

看完这个视频,发誓再也不当榜一大哥了

最近在AI界有个视频很火&#xff0c;网友看完之后表示&#xff1a;十年前担心网友是抠脚大汉&#xff0c;十年后担心网友是抠脸大汉。 软件简介 该视频使用的软件为DeepFacelive,一个可以在直播过程和视频通话时进行实时换脸的本地工具。DeepFaceLive 建立在 DeepFaceLab 的基…

以太网口硬件知识分享

一、了解网口通信基本原理 实现网络通信实质上是PHY与MAC及RJ45接口实现信号传输。MAC 就是以太网控制器&#xff0c;MAC属于数据链路层&#xff0c;主要负责把数据封装成帧&#xff0c;对帧进行界定实现帧同步。对MAC地址和源MAC地址及逆行相应的处理并对错误帧进行处理。PHY…