仿真手写Spring核心原理v1.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的存亡而存亡。

猜你喜欢

转载自www.cnblogs.com/ZekiChen/p/12782443.html