自己实现SpringMVC 底层机制[二]

文章目录

  • 自己实现SpringMVC 底层机制[二]
    • 实现任务阶段3- 从web.xml 动态获取myspringmvc.xml
      • 分图析示意
      • 代码实现
    • 实现任务阶段4- 完成自定义@Service 注解功能。
      • 分析示意图
      • 代码实现
      • 完成测试(启动Tomcat, 自动加载MyDispatcherServlet, 完成IOC 容器的注入)。

自己实现SpringMVC 底层机制[二]

实现任务阶段3- 从web.xml 动态获取myspringmvc.xml

前面我们加载myspringmvc.xml 是硬编码, 现在做活, 从web.xml 动态获取,

分图析示意

MyDispatcherServlet 在创建并初始化MyWebApplicationContext,动态的从web.xml 中获取到配置文件.

代码实现

修改my-springmvc\src\main\java\com\myspringmvc\context\MyWebApplicationContext.java

public class MyWebApplicationContext {//定义属性classFullPathList, 保存扫描包/子包的类的全路径private List<String> classFullPathList =new ArrayList<>();//定义属性ioc, 存放反射生成的Bean对象 /Controller/Servicepublic ConcurrentHashMap<String, Object> ioc =new ConcurrentHashMap<>();//无参构造器public MyWebApplicationContext() {}private String configLocation;//属性,表示spring容器配置文件public MyWebApplicationContext(String configLocation) {this.configLocation = configLocation;}//编写方法,完成自己的spring容器的初始化public void init() {//这里是写的固定的spring容器配置文件=>做活//String basePackage = XMLParser.getBasePackage("myspringmvc.xml");String basePackage =XMLParser.getBasePackage(configLocation.split(":")[1]);//这时basePackage => com.controller,com.serviceString[] basePackages = basePackage.split(",");//判断包是否为空if (basePackages.length > 0) {//遍历basePackages, 进行扫描for (String pack : basePackages) {scanPackage(pack);//扫描包保存路径放在集合,便于后面进行反射到容器}}System.out.println("扫描后的= classFullPathList=" + classFullPathList);//测试得到的路径集合是否正确//将扫描到的类, 反射到ico容器executeInstance();System.out.println("扫描后的 ioc容器= " + ioc);}
}

修改my-springmvc\src\main\java\com\myspringmvc\servlet\MyDispatcherServlet.java

@Overridepublic void init(ServletConfig servletConfig) throws ServletException {//获取到web.xml中的 contextConfigLocation/*<init-param><param-name>contextConfigLocation</param-name><param-value>classpath:myspringmvc.xml</param-value></init-param>*/String configLocation =servletConfig.getInitParameter("contextConfigLocation");//创建自己的spring容器myWebApplicationContext =new MyWebApplicationContext(configLocation);myWebApplicationContext.init();//完成容器初始化//调用 initHandlerMapping , 完成url和控制器方法的映射initHandlerMapping();//输出handlerListSystem.out.println("handlerList初始化的结果= " + handlerList);}

完成测试(启动tomcat 方式, 修改后,redeploye 即可生效)。

实现任务阶段4- 完成自定义@Service 注解功能。

功能说明: 如果给某个类加上@Service, 则可以将其注入到我们的Spring 容器

分析示意图

给Service 类标注@Service, 可以将对象注入到Spring 容器中。

可以通过接口名支持多级类名来获取到Service Bean。

如下

//扫描后的ioc
ioc={monsterService=com.service.impl.MonsterServiceImpl@6323a1c1,
orderController=com.controller.OrderController@4c96ec4f,
monsterController=com.controller.MonsterController@81664b3}

代码实现

创建my-springmvc\src\main\java\com\entity\Monster.java

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 +'}';}
}

创建my-springmvc\src\main\java\com\myspringmvc\annotation\Service.java

// Service 注解,用于标识一个Service对象,并注入到spring容器
@Target(ElementType.TYPE)//该注解只能声明在一个类前
@Retention(RetentionPolicy.RUNTIME)//不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Documented//  java 在生成文档,显示注解
public @interface Service {String value() default "";
}

创建my-springmvc\src\main\java\com\service\MonsterService.java

public interface MonsterService{//增加方法-返回monster列表public List<Monster> listMonster();
}

创建my-springmvc\src\main\java\com\service\impl\MonsterServiceImpl.java

@Service
public class MonsterServiceImpl implements MonsterService {@Overridepublic List<Monster> listMonster() {//这里模拟数据->DBList<Monster> monsters =  new ArrayList<>();monsters.add(new Monster(100, "牛魔王", "芭蕉扇", 400));monsters.add(new Monster(200, "老猫妖怪", "抓老鼠", 200));return monsters;}
}

修改my-springmvc\src\main\resources\myspringmvc.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans><!--指定要扫描的基本包以及子包的java类--><component-scan base-package="com.controller,com.service"></component-scan>
</beans>

修改my-springmvc\src\main\java\com\myspringmvc\context\MyWebApplicationContext.java

 //编写方法,将扫描到的类, 在满足条件的情况下,反射到ioc容器
//实例化扫描到的类->创建对象->放入到IOC 容器[ConcurrentHashMap]public void executeInstance() {//判断是否扫描到类if (classFullPathList.size() == 0) {//说明没有扫描到类return;}try {//遍历classFullPathList,进行反射for (String classFullPath : classFullPathList) {Class<?> clazz = Class.forName(classFullPath);//说明当前这个类有@Controllerif (clazz.isAnnotationPresent(Controller.class)) {//得到类名首字母小写String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase() +clazz.getSimpleName().substring(1);ioc.put(beanName, clazz.newInstance());} //如果有其它的注解,可以扩展 , 来处理@Serviceelse if (clazz.isAnnotationPresent(Service.class)) {//如果类有@Serivce注解//先获取到Service的value值=> 就是注入时的beanNameService serviceAnnotation =clazz.getAnnotation(Service.class);String beanName = serviceAnnotation.value();if ("".equals(beanName)) {//说明没有指定value, 我们就使用默认的机制注入Service//可以通过接口名/类名[首字母小写]来注入ioc容器//1.得到所有接口的名称=>反射Class<?>[] interfaces = clazz.getInterfaces();Object instance = clazz.newInstance();//2. 遍历接口,然后通过多个接口名来注入for (Class<?> anInterface : interfaces) {//接口名->首字母小写String beanName2 = anInterface.getSimpleName().substring(0, 1).toLowerCase() +anInterface.getSimpleName().substring(1);ioc.put(beanName2, instance);}} else {//如果有指定名称,就使用该名称注入即可ioc.put(beanName, clazz.newInstance());}}}} catch (Exception e) {e.printStackTrace();}}

完成测试(启动Tomcat, 自动加载MyDispatcherServlet, 完成IOC 容器的注入)。

扫描后的ioc= {monsterService=com.service.impl.MonsterServiceImpl@6323a1c1,
orderController=com.controller.OrderController@4c96ec4f,
monsterController=com.controller.MonsterController@81664b3}

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

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

相关文章

springboot集成logback按日志级别按天保存

演示结果 集成logback后项目启动控制台不会有日志输出 生成的日志文件路径windows上是默认D盘,linux上可自定义 代码实现 pom.xml <dependency><groupId>ch.qos.logback</groupId>

C# Modbus通信从入门到精通(21)——Modbus TCP协议原理

Modbus TCP是走网口的&#xff0c;也可以在同一时间内有多个从站访问主站&#xff0c;并且通过Modbus事务处理标识来区分同一时刻的不同Modbus事务&#xff0c;这是区别于Modbus ASCII和Modbus RTU的地方。 1、访问模式&#xff1a; Modbus客户端通常输入Modbus服务器的IP地址…

Server - 调用 K8S 集群 GPU 环境运行算法脚本

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131899662 Kubeflow 是基于 Kubernetes 的机器学习工具包&#xff0c;提供了一套技术栈&#xff0c;包含了很多组件&#xff0c;用于支持…

SQL SERVER安装

其中服务器名称输入./自己本机电脑名称. nchar类型一个单位可以放一个汉字-------长度短的补空格一个字节8位一个汉字两个字节 char类型两个单位可以放一个汉字 nvarchar类型是可变长度-----------长度短不会补空格 varchar类型是可变长度两个单位可以放一个汉字---------…

Istio Pilot源码学习(三):xDS的异步分发

本文基于Istio 1.18.0版本进行源码学习 5、xDS的异步分发 DiscoveryService主要包含下述逻辑&#xff1a; 启动GRPC Server并接收来自Envoy端的连接请求接收Envoy端的xDS请求&#xff0c;从ConfigController和ServiceController中获取配置和服务信息&#xff0c;生成响应消息…

文心一言 VS 讯飞星火 VS chatgpt (64)-- 算法导论6.5 3题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;64&#xff09;-- 算法导论6.5 3题 三、要求用最小堆实现最小优先队列&#xff0c;请写出 HEAP-MINIMUM、HEAP-EXTRACT-MIN、HEAP DECREASE-KEY 和 MIN-HEAP-INSERT 的伪代码。 文心一言&#xff1a; 以下是使用最小堆实现最小…

国内攻克OLED屏幕修复术,成本暴降2/3不用拆机换屏

连着许多年各家手机发布会&#xff0c;屏幕基本是会花大精力宣传的三大件之一 也对&#xff0c;无论是外观还是实际的视觉、操作体验&#xff0c;屏幕都是非常重要的一环。 屏幕素质越来越高&#xff0c;用着也的确更爽了&#xff0c;但也越来越不敢摔了。 普普通通的一块 60…

SNMP协议是什么?

SNMP协议是什么&#xff1f; 简单网络管理协议&#xff08;Simple Network Management Protocol&#xff0c;SNMP&#xff09;是由互联网工程任务组定义的一套网络管理协议。该协议是基于简单网关监视协议&#xff08;Simple Gateway Monitor Protocol&#xff0c;SGMP&#x…

ChatGPT助力校招----面试问题分享(十二)

1 ChatGPT每日一题&#xff1a;运算放大器与比较器的区别 问题&#xff1a;运算放大器与比较器的区别 ChatGPT&#xff1a;运算放大器和比较器都是电子电路中常用的模拟电路元件&#xff0c;但它们的设计和应用略有不同。下面是两者的主要区别&#xff1a; 功能不同&#xf…

服务器负载均衡算法有哪些

算法举例 服务器负载均衡算法是用于分配网络流量到多个服务器的策略&#xff0c;以实现负载均衡和提高系统性能。以下是一些常见的服务器负载均衡算法的详细说明&#xff1a; 轮询&#xff08;Round Robin&#xff09;算法&#xff1a; 轮询算法是最简单且常见的负载均衡算法之…

DevOps系列文章之 Git知识大全

常用命令 其他参数 --inital-branch 初始化的分支 --bare 创建一个裸仓库&#xff08;纯 Git 目录&#xff0c;没有工作目录&#xff09; --template 可以通过模板来创建预先建好的自定义 git 目录 常见 Git 配置 用户名配置 git config --global user.name "yourname&qu…

cmder 使用简介

文章目录 1. cmder 简介2. 下载地址3. 安装4. 配置环境变量5. 添加 cmder 到右键菜单6. 解决中文乱码问题 1. cmder 简介 cmder 是一个增强型命令行工具&#xff0c;不仅可以使用 windows 下的所有命令&#xff0c;更爽的是可以使用 linux的命令, shell 命令。 2. 下载地址 …

选择合适的图表,高效展现数据魅力

随着大数据时代的来临&#xff0c;数据的重要性愈发凸显&#xff0c;数据分析和可视化成为了决策和传递信息的重要手段。在数据可视化中&#xff0c;选择合适的图表是至关重要的一环&#xff0c;它能让数据更加生动、直观地呈现&#xff0c;为观众提供更有说服力的信息。本文将…

模型构建——使用逻辑回归构建模型,lightGBM进行特征筛选

1、模型构建流程 1.1 实验设计 新的模型要跟原有方案对比&#xff0c;而且是通过实验证明&#xff0c;特别注意模型和策略不能同时调整。一般实验设计包含以下流程&#xff1a; 问题&#xff1a;业务稳定后&#xff0c;可以去掉人工审核吗&#xff1f; 答&#xff1a;不可以…

c语言练手项目【编写天天酷跑游戏2.0】EASYX图形库的运用。代码开源,素材已打包

天天酷跑项目的开发 项目前言 项目是基于Windows&#xff0c;easyX图形库进行开发的&#xff0c; 开发环境&#xff1a;Visual Studio 2022 项目技术最低要求&#xff1a; 常量&#xff0c;变量&#xff0c;数组&#xff0c;循环&#xff0c;函数。 文章目录 天天酷跑项目的…

超详细-Vivado配置Sublime+Sublime实现Verilog语法实时检查

目录 一、前言 二、准备工作 三、Vivado配置Sublime 3.1 Vivado配置Sublime 3.2 环境变量添加 3.3 环境变量验证 3.4 Vivado设置 3.5 配置验证 3.6 解决Vivado配置失败问题 四、Sublime配置 4.1 Sublime安装Package Control 4.2 Sublime安装Verilog插件 4.3 安装语…

#pragma region用法

简介 #pragma region 是VS(Visio Studio)所特有的预处理语法&#xff08;其他IDE或者Cmake会报错&#xff09;&#xff0c;其可以用来收缩或者展开一段代码。 #pragma region MyRegion// ...Code content #pragma endregion 其中&#xff0c;MyRegion 即给这代码块所定义的名…

【计算机网络】简易TCP网络小程序

文章目录 1. 简易TCP网络程序1.1 服务端1.1.1 服务端创建套接字1.1.2 服务端绑定1.1.3 服务端监听1.1.4 服务端获取连接1.1.5 服务端处理请求 1.2 客户端1.2.1 客户端创建套接字1.2.2 客户端连接服务器1.2.3 客户端发起请求 1.3 服务器测试1.4 单执行流服务器的弊端 2. 多进程版…

【Java】 服务器cpu过高如何排查和解决?

文章目录 前言一、常见能够引起CPU100%异常的情况都有哪些&#xff1f;二、服务器CPU使用率飙升异常&#xff0c;黄金4步排查法三、排查 CPU 故障的常用命令四、什么场景会造成 CPU 低而负载确很高呢&#xff1f;五、监控发现线上机器内存占用率居高不下&#xff0c;如何分析进…