本章博客借鉴于《架构探险-从零开始写Java Web框架》。
代码详情spring-framework
知识前提
所有的类都要加载,你要使用什么类都要加载进去才可以使用。所有你要有一个自己
的类加载器来加载你的类。
你需要一个Servlet类,这个类可以接受外部请求。默认的是DispathcharServlet这个类。
他负载来获得外部请求。你需要自己写一个servlet类。
spring创建bean的方式
1:调用构造器创建Bean
2:调用静态工厂方法创建Bean
3:调用实例工厂方法创建Bean
spring IOC理论
IoC理论:借助于“第三方”实现具有依赖关系的对象之间的解耦,
1) 软件系统在没有引入IoC容器之前,对象A依赖对象B,那么A对象在实例化或者运行到某一点的时候,自己必须主动创建对象
B或者使用已经创建好的对象B,其中不管是创建还是使用已创建的对象B,控制权都在我们自己手上。
2)如果软件系统引入了Ioc容器之后,对象A和对象B之间失去了直接联系,所以,当对象A实例化和运行时,如果需要对象B的
话,IoC容器会主动创建一个对象B注入到对象A所需要的地方。
3)通过前面的对比,可以看到对象A获得依赖对象B的过程,由主动行为变成了被动行为,即把创建对象交给了IoC容器处理,控
制权颠倒过来了,这就是控制反转的由来!
IOC原理 这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,即所谓反转。
springmvc的流程
1.用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2.DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得
该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain
对象的形式返回;
3.DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,
此时将开始执行拦截器的preHandler(...)方法)
4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,
根据你的配置,
Spring将帮你做一些额外的工作:
HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5.Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6.根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)
返回给DispatcherServlet ;
7.ViewResolver 结合Model和View,来渲染视图
8.将渲染结果返回给客户端
错误解答
启动程序时,访问出现java.lang.NoClassDefFoundError,
Could not initialize class com.spring.helper.ControllerHelper信息为什么?
这是因为无法正常初始化这个类。在自己的spring的框架中我们是自己的类加载器。有可能遇到
自己加载时没有报错但是运行时无法找到实际的类运行。
下载代码
本文中需要git的知识,如果不会,请自行google.
git clone git@github.com:jack-zdl/spring-framework.git
代码详情
1 处理配置文件的配置参数。
smart.properties 配置文件
ConfigConstant 常量类,匹配配置文件的配置参数
ConfigHelper 获取配置文件的参数
2 开发一个类加载器
ClassUtil 类操作工具类,提供类操作相关方法
Controller Action Service Inject 注解类
ClassHelper 类操作助手类 获取应用包下的所有类,
3 实现Bean容器
ReflectionUtil 反射类 封装Java反射相关的API
BeanHelper bean的容器 ,将调用ClassHelper类的getBeanClassSet,获得类,通过
调用ReflectionUtil的newInstance方法。
4 实现IOC,如何实例化Controller中的service实例
IocHelper 先通过BeanHelper获取所有Bean Map(是一个Map<Class<?>,Object> 结构,
记录类和对象的关系)。然后遍历这个映射关系,分别取出Bean类与Bean实例进而
而通过反射获取类中所有的成员变量,继续遍历这些成员变量。再循环中判断当前
是否带有Inject注解,若带有此注解,则从Bean Map中根据Bean类取出Bean实例。
最后通过ReflectionUtil修改当前变量的值。
5 加载Controlller
Request 外界请求参数
Hander 封装Action信息
ControllerHelper 通过它我们可以获取Controller注解的类,可以通过反射获取该类中
所有带有Action注解方法,获取Action注解中的表达式,进而获取请求
方法,请求路径。将Request和Hander建立映射关系。放入Action Map中。
并提供根据请求方法和路径获得处理对象的方法。
6 初始化框架
HelperLoader 入口程序加载他们,加载他们的静态块。
DispathcharServlet 它来处理所有的请求,从HttpServletRequest对象中获取请求方法和
请求路径,通过ControllerHelper#getHander方法获取Hander对象。当我们
拿到Hander对象获取Controller类,进而通过BeanHelper.getBean方法获取
Controller的实例对象。
spring mvc流程
在一个spring框架启动时,会先初始化一个Servlet。这里是DispathcharServlet类。
首先执行DispathcharServlet类的init方法。
1 | //初始化框架 |
在这里执行HelperLoader的init方法。加载相应的Helper。
初始化Class操作助手类 获取应用包下的所有类
初始化Bean的助理类,获得bean的实例。
初始化依赖注入助手类,获得类的所有成员变量。
初始化Controller助手类。控制器助手类。
基本上初始化加载时就完成工作了。
1 | public static void init(){ |
第一段总结
基本我们知道这个工程时通过初始化DispathcharServlet,然后执行类加载器的方法,执行
加载我们必须使用的ClassHelper,BeanHelper,IocHelper,ControllerHelper,
这里初始化ClassHelper你可以获得你要扫描路径的所有类。
这里初始化BeanHelper你可以根据扫描的类通过反射机制来获得所有的实例,即bean对象。
这里初始化IocHelper来解决依赖注入,即对象直接的关系。Controller中实现Service对象。