首页 > 编程语言 > 详细

仿真手写Spring核心原理v1.0

时间:2020-04-28 00:44:50      阅读:59      评论:0      收藏:0      [点我收藏+]

一、实现思路

技术分享图片

二、工程结构

技术分享图片

三、自定义配置

1、配置application.properties文件

为了解析方便,用application.properties来代替Spring的核心配置文件application.xml,具体配置内容如下:

技术分享图片

2、配置web.xml文件

所有依赖于Web容器的项目,都是从读取web.xml文件开始的。先配置好web.xml中的内容:

其中MyDispatcherServlet是自己模拟Spring实现的核心功能类。

技术分享图片

四、自定义注解

@MyController注解:

技术分享图片 

@MyRequestMapping注解:

技术分享图片

 @MyRequestParam注解:

技术分享图片

 @MyService注解:

技术分享图片

 @MyAutowired注解:

技术分享图片

 另外,这里再补充些Java中元注解相关的知识:

技术分享图片

五、在业务代码上加上我们自定义的注解

定义一个DemoService接口:

技术分享图片

定义一个DemoServiceImpl实现类:

技术分享图片

定义一个DemoController类:

技术分享图片

至此,配置阶段就已经完成。

六、容器初始化和运行阶段

定义一个MyDispatcherServlet类(仿造SpringMVC的前端控制器):

技术分享图片

① 实现v1版本

初始化阶段:

采用了常用的设计模式(工厂模式、单例模式、委派模式、策略模式),将init()方法中的代码进行封装。按照之前的实现思路,先搭基础框架,再填补具体代码:

技术分享图片

声明全局的成员变量,其中IOC容器就是注册式单例的具体案例:

技术分享图片

 实现doLoadConfig()方法:

技术分享图片

 实现doScanner()方法:

技术分享图片

实现doInstance()方法,该方法就是工厂模式的具体体现:

技术分享图片

为了处理方便,自己实现了toLowerFirstCase()方法,用来实现类名首字母小写,具体代码如下:

技术分享图片

实现doAutowired()方法:

技术分享图片

实现initHandlerMapping()方法,handlerMapping就是策略模式的应用案例(省去大量if...else if...):

技术分享图片

运行阶段:

技术分享图片

doPost()方法中用了委派模式,委派模式的具体逻辑在doDispatch()方法中:

技术分享图片

② 实现v2版本:

在v1版本中,基本功能已经完全实现,但代码的优雅程度还不如人意。比如url参数还不支持强制类型转换,在运行阶段还需要通过反射获取Method方法对应的Controller类名、以及加了@RequestParam注解的方法参数,消耗系统性能。在v2版本中继续优化,把运行阶段的反射调用前移到初始化阶段。

首先修改web.xml文件,将v1版本的MyDispatcherServlet改成v2版本:

技术分享图片

接着改造HandlerMapping,在真实的Spring源码中,HandlerMapping其实是一个List而非Map,List中的元素是一个自定义的类型。现在我们来仿真写一段代码,先定义一个内部类HandlerMapping:

技术分享图片

技术分享图片

然后,优化HandlerMapping容器的结构,代码如下:

技术分享图片

修改initHandlerMapping()方法:

技术分享图片

修改doDispatch()方法:

技术分享图片

定义一个convert()方法,主要负责url参数的强制类型转换:

技术分享图片

定义一个getHandler()方法,主要负责匹配handlerMapping容器中是否有对应的url:

技术分享图片

至此,手写Mini版SpringMVC框架就已全部完成。

运行结果演示:

测试query()方法:

技术分享图片

技术分享图片

测试add()方法:

技术分享图片

测试remove()方法: 

技术分享图片

当然,真正的Spring要复杂很多,这里主要通过手写的形式,了解Spring的基本设计思路以及设计模式如何应用,后续会继续手写更加高仿真的Spring v2.0版本。

七、面试题

1、提问:Spring中的Bean是线程安全的吗?

思考,Spring中的Bean是哪里来的?通过包扫描对应的类,利用反射实例化出来的,并且缓存在IOC容器中。Spring并没有对你的Bean做任何处理,Bean是不是线程安全取决于用户编写的Bean本身

2、提问:Spring中的Bean是如何被回收的?

其实就是Spring中的Bean的生命周期问题,Bean设置不同的作用域对应不同的生命周期,不同的生命周期对应不同的回收时间。作用域包括singleton、prototype、request、session、globalSession。可以在xml中配置,例如:

技术分享图片

如果设置为prototype,即多例模式。每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XXBean(),用完了就被GC回收了。

如果设置为request,那对应的Bean就会存在于一次请求里面。

如果设置为session,那对应的Bean就会存在于一次会话里面。

如果设置为globalsession,那对应的Bean就会存在于整个Web应用中。

Spring中的Bean默认是singleton,即单例模式。GC回收原则:当Bean没有被任何地方引用的时候。所以,当Spring本身不消失,自然而然IOC容器也不会消失,那么IOC容器中对应的Bean实例也不会消失。所以,此时的Bean是全局存在的,或者说随着Spring的存亡而存亡。

仿真手写Spring核心原理v1.0

原文:https://www.cnblogs.com/ZekiChen/p/12782443.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!