自己实现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地址…

简单模拟Mybatis通过注解查询SQL

通过自定义注解&#xff0c;简单模拟Mybatis通过注解查询SQL。 首先&#xff0c;创建自定义注解MyDao和MySelect。 MyDao.java Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) public interface MyDao {String[] value() default {}; }MySelect.java Targ…

AI面试官:LINQ和Lambda表达式(一)

AI面试官&#xff1a;LINQ和Lambda表达式&#xff08;一&#xff09; 当面试官面对C#中关于LINQ和Lambda表达式的面试题时&#xff0c;通常会涉及这两个主题的基本概念、用法、实际应用以及与其他相关技术的对比等。以下是一些可能的面试题目&#xff0c;附带简要解答和相关案…

HTML <option> 标签

实例 创建带有 4 个选项的选择列表: <select><option value ="volvo">Volvo</option><option value ="saab">Saab</option><option value="opel">Opel</option><option value="audi"…

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;用于支持…

使用RestTemplate访问内部服务时返回的json字符串未做转换处理之后再次返回json字符到前台导致json字符串无法解析的解决办法

1. 以下是使用RestTemplate调用接口的方法 RequestMapping("/getQrList") //获取qrlable列表String getQrList(Qr qr) {//返回的数据本身就是 ResponBody也就是json&#xff0c;当前方法再次返回json&#xff0c;就会导致导出时无法解析数据&#xff08;table是能…

SQL SERVER安装

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

GStreamer Basic tutorial 学习笔记(十三)

1 播放速度 GStreamer提供了两种改变播放速度的机制&#xff1a;步进事件&#xff08;Step Events&#xff09;和搜索事件&#xff08;Seek Events&#xff09;。步进事件允许跳过一定量的媒体&#xff0c;并改变随后的播放速度&#xff08;只能为正值&#xff09;。搜索事件还…

“深入解析Spring Boot:从入门到实战“

标题&#xff1a;深入解析Spring Boot&#xff1a;从入门到实战 摘要&#xff1a;本篇博客将深入解析Spring Boot&#xff0c;从入门到实战&#xff0c;帮助读者了解Spring Boot的核心概念、特性和使用方法&#xff0c;并通过示例代码演示如何使用Spring Boot开发一个简单的We…

Python3 unittest学习

Python3 unittest学习 unittest单元测试框架基本结构执行测试普通方式执行通过unittest模块执行 跳过测试与预期失败使用子测试区分测试迭代类与函数class unittest.TestCase(methodNamerunTest)用于运行测试的方法断言方法其他方法和属性 class unittest.IsolatedAsyncioTestC…

JVM五大内存模型

什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一个虚构出来的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等。 JVM的作用 Java语言使用Java虚拟机屏蔽了与具体平台相关的信息&#xff0c;使得Jav…

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…

【传感器】应用充气泵方案的压力传感器

压力传感器&#xff0c;是指以膜片装置&#xff08;不锈钢膜片、硅酮膜片等&#xff09;为媒介&#xff0c;用感压元件对气体和液体的压力进行测量&#xff0c;并转换成电气信号输出的设备。其原理是半导体压电阻抗扩散压力传感器是在薄片表面形成半导体变形压力&#xff0c;通…

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…

TC3XX - MCAL知识点(十一):WDG EB-tresos配置说明与代码浅析

目录 1、概述 1.1、简介 1.2、Safety Watchdog 1.3、CPU Watchdogs 1.4、看门狗定时器的功能列表