实现SpringMVC底层机制(二)

news2024/11/25 0:39:57

文章目录

    • 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;
    }

    @Override
    public 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);
                    //获取注解的value
                    String 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)) {
                    //得到这个注解的value
                    AutoWired 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.coloradmin.cn/o/1626757.html

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

相关文章

嵌入式Linux学习——Ubantu初体验

Ubuntu 和Windows 的最大差别 Windows中的每一个分区都对应着一个盘符&#xff0c;盘符下可以存放目录与文件&#xff0c;而在Ubantu中没有盘符的概念&#xff0c;只有目录结构。实际上不同的目录可能挂载在不同的分区之下&#xff0c;如果想要查看当前目录位于磁盘的哪个分区…

代码随想录算法训练营Day9 | 双指针总结归纳:

截止目前为止&#xff0c;已经刷过十道有关于双指针的题了&#xff1a; 1.对于数组而言&#xff0c;数组上的元素不能做到删除&#xff0c;只能进行覆盖&#xff0c;通过两个指针在一个for循环下完成两个for循环的工作&#xff0c;提升了效率 2.字符串中定义两个指针&#xff…

第三篇:Python编程基础:掌握核心语法与开发技巧

Python编程基础&#xff1a;掌握核心语法与开发技巧 1 引言 在这个信息化迅速蔓延的世界中&#xff0c;Python语言如同钥匙一般开启了通往各种可能性的大门。无论你是数据科学家、网络工程师、机器学习专家&#xff0c;还是仅仅对自动化办公感兴趣的办公室人员&#xff0c;Pyt…

汽车驾驶3D模拟仿真展示系统更立体直观

随着新能源汽车的普及&#xff0c;它已成为现代生活中不可或缺的交通工具。并且国产车的崛起&#xff0c;其设计与零部件制造水平已能与合资车相媲美&#xff0c;因此汽车维修技能的学习变得尤为重要。汽车维修3D仿真教学软件应运而生&#xff0c;为广大学员提供了一个直观、高…

【产品经理修炼之道】- 携程酒店业务

这篇文章里&#xff0c;作者以携程为参照对象进行了业务分析&#xff0c;一起来看看本文作者关于携程酒店业务的思考。想了解OTA、或者酒店业务的同学们&#xff0c;或许可以来看看本文的思路。 本文是以携程为参照对象做的一个业务分析&#xff0c;系列一共有三期&#xff0c…

【鸿蒙】通知

一、概要 Android的Notification。 说到通知&#xff0c;就想到了推送。 通知这块可以做到不像Android一样需要集成各家厂商的推送了&#xff0c;不知道是否有建立独立的推送系统 这是官网上介绍的跨APP进行的IPC通知。实际在Android开发过程中&#xff0c;可能这种场景会相对…

【产品经理修炼之道】- 导航架构设计

目录 一、导航是什么 二、导航的作用 三、导航的分类 四、导航菜单的广度与深度 五、导航的颜色 六、导航的形态 七、导航的研究 八、导航的设计 九、导航改版案例分享 总结 每个网页的设计都需要包括导航&#xff0c;那么导航架构该如何设计&#xff1f;作者结合之前…

dwc3控制器是怎么处理otg

概念 在OTG中&#xff0c;初始主机设备称为A设备&#xff0c;外设称为B设备。可用电缆的连接方式来决定初始角色。两用设备使用新型Mini-AB插座&#xff0c;从而使Mini-A插头、Mini-B插头和Mini-AB插座增添了第5个引脚&#xff08;ID&#xff09;&#xff0c;以用于识别不同的…

怎么从回收站恢复已删除的文件?(5种恢复方法)

回收站是电脑操作系统中的一个特殊目录&#xff0c;用于存储被删除但尚未完全清除的文件和文件夹。当用户删除文件或文件夹时&#xff0c;它们并不立即从硬盘驱动器中移除&#xff0c;而是被移动到回收站。这样设计的目的是为了给用户一个“第二次机会”&#xff0c;如果他们意…

python-excel自动化-openpyxl

openpyxl学习笔记 创建或打开表格存储和遍历数据设置单元格风格过滤器和排序更改工作表的背景颜色合并单元格冻结窗口数字格式公式图像图表条形图折线图散点图 创建或打开表格 # 创建 import datetime from openpyxl import Workbook # 实例化 wb Workbook() # 激活 work…

融合卷积和注意力机制:有效整合它们优势的方法概述

卷积与注意力机制的结合 1. 介绍2. 模型学习偏差及其后果2.1 全连接层2.2 卷积层2.3 自注意力层 3. 融合卷积与注意力的学习方法3.1 Squeeze-and-Excitation网络3.2 卷积块注意力模块3.3 相对自注意力3.4 注意力增强卷积网络3.5 使用变换器进行端到端目标检测3.6 CvT&#xff1…

ssm083化妆品配方及工艺管理系统的设计与实现+jsp

化妆品配方及工艺管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本化妆品配方及工艺管理系统就是在这样的大环境下诞生&#xff0c;其可…

自动评论轻松增粉!抖音新技能来了

在如今这个信息爆炸&#xff0c;流量至上的时代&#xff0c;如何快速吸引新粉丝并保持互动性成为了许多内容创作者的心头大患。想象一下&#xff0c;如果你有一款神奇的工具&#xff0c;能让你在抖音上自动互动&#xff0c;轻松吸引关注&#xff0c;岂不是美哉&#xff1f;今天…

Spring Cloud Alibaba Sentinel 使用

初识Sentinel Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址&#xff1a; home | Sentinel 需要了解的概念 簇点链路 在学习 Sentinel 的使用之前&#xff0c;我们有必要首先了解一下簇点链路。当请求进入微服务时&#xff0c;首先会访Controller、Service、Ma…

原生js实现一个简化版的h函数

原生js实现一个简化版的h函数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&…

ChatGPT智能对话和MidjourneyAI画画系统源码运营版+完整教程

今天给大家带来一款可以帮你赚米的AI智能系统。这款系统将AI智能会话及AI画画功能合二为一&#xff0c;对接了大名鼎鼎的ChatGPT接口及Midjourney两个王牌接口。另外后台还集成了国内外几十个AI大模型及AI绘画接口&#xff08;输入文字就可以快速生成高清图片&#xff09;&…

PHP 函数的命名空间是否会影响执行顺序?

在 php 中&#xff0c;函数命名空间一般不会影响执行顺序。执行顺序通常由文件顺序或函数调用顺序决定。即使函数位于不同的命名空间中&#xff0c;只要它们在同一文件中&#xff0c;它们就会按照定义顺序执行。 PHP 函数命名空间是否会影响执行顺序&#xff1f; 简介 在 PHP…

AI 边缘计算平台 - 嘉楠堪智 CanMV K230 开箱

CanMV-K230 开发板采用的是嘉楠科技 Kendryte 系列 AIoT 芯片中的最新一代 SoC 芯片 K230。该芯片采用全新的多异构单元加速计算架构&#xff0c;最新高性能 RISC-V CPU 内置双核玄铁 C908 CPU, 主频高达 1.6GHz&#xff1b;是全球首款支持 RISC-V Vector 1.0 标准的商用 SoC&a…

某翻译平台翻译接口逆向之webpack学习

逆向网址 aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tLw 逆向链接 aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tLyMv 逆向接口 aHR0cHM6Ly9kaWN0LnlvdWRhby5jb20vd2VidHJhbnNsYXRl 逆向过程 请求方式 POST 逆向参数 sign c168e4cb76169e90f82d28118dbd24d2 接口请求结果解密 过程分析 根据XHR…

Transformer模型详解01-Word Embedding

文章目录 前言Transformer 整体结构Transformer 的输入单词 Embedding原理CBOW 模型one-hot构建 CBOW 训练数据集构建 CBOW 神经网络训练 CBOW 神经网络 Skip-gram 模型one-hot构建 Skip-gram训练数据集训练 Skip-gram神经网络 Word2Vec实例数据训练保存和加载 前言 Transform…