本文共 10243 字,大约阅读时间需要 34 分钟。
深度模仿 Spring 源码,完成 IOC \ DI 操作,较上一个版本,内容更加贴近 Spring,主要也是先学习设计思想,为后续学习源码做铺垫。通过简单易懂的代码学习思想,带着思想去理解 Spring,加深学习效果,更加容易吸收。
在上一篇中,我们已经知道 SpringMVC 的入口是 DispatcherServlet,我们通过自己手写的DispatcherServlet类继承了 HttpServlet类,并在 init 方法中完成了一系列的初始化动作。而在我们使用的 Spring 经验中,我们见的最多的就是 ApplicationContext,似乎Spring 托管的所有的实例 Bean都可以通过getBean()方法来获得。那么ApplicationContext又是从何而来的呢?从 Spring 的源码中,我们可以通过类图看到DispatcherServlet的关系网如下:
DispatcherServlet 继承了FrameworkServlet,FrameworkServlet继承了 HttpServletBean,HttpServletBean继承了 HttpServlet。在HttpServletBean的 init()方法中调用了FrameworkServlet中的 initServletBean()方法,在initServletBean()方法中初始化了 webApplicationContext实例。在初始化webApplicationContext实例的同时,又调用了DispatcherServlet重写的onRefresh()方法,在DispatcherServlet重写的onRefresh()方法中通过调用 initStrategies()完成了 初始化SpringMVC的九大组件。
其实,上面复杂的调用关系,我们可以简单的得出一个结论:就是在 Servlet的init()方法中初始化了IOC容器和SpringMVC所依赖的九大组件。
#定义需要扫描的包路径scanPackage=com.mmt.imitate
只引入一个 servlet 依赖的包
2.4 javax.servlet servlet-api ${servlet.api.version} provided org.projectlombok lombok 1.16.10 org.slf4j slf4j-api 1.7.25 ch.qos.logback logback-classic 1.2.3
mmt imitate Web Application mmt-imitate com.mmt.imitate.spring.framework.webmvc.servlet.DispatcherServlet contextConfigLocation classpath:application.properties 1 mmt-imitate /*
public class DispatcherServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // } @Override public void init(ServletConfig config) throws ServletException { super.init(config); }}
annotation 注解与上一篇稳重中的版本一致,可直接使用mini 版里面写的,这里直接复制过来
自定义 @MmtController
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MmtController { String value() default "";}
自定义 @MmtService
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MmtService { String value() default "";}
自定义 @MmtAutowired
@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MmtAutowired { String value() default "";}
自定义 @MmtRequestMapping
@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MmtRequestMapping { String value() default "";}
自定义 @MmtRequestParam
@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MmtRequestParam { String value() default "";}
BeanDefinition
package com.mmt.imitate.spring.framework.beans.config;import lombok.Data;@Datapublic class BeanDefinition { private String factoryBeanName; private String beanClassName;}
BeanWrapper
package com.mmt.imitate.spring.framework.beans;public class BeanWrapper { /** * 原始对象 */ private Object wrapperInstance; /** * 对应的 class */ private Class wrappedClass; public BeanWrapper(Object instance) { this.wrapperInstance = instance; this.wrappedClass = instance.getClass(); } public Object getWrapperInstance() { return wrapperInstance; } /** * 返回代理以后的 class,有可能是 $Proxy0 * @return */ public Class getWrappedClass() { return wrappedClass; }}
ApplicationContext
package com.mmt.imitate.spring.framework.context;/** * 完成 bean 的创建和 DI */public class ApplicationContext { // TODO 先将类创建好,后面再完善}
同上一篇 mini 版一样,我们在上一版的基础上进行优化,这次,我们使用ApplicationContext 来完成 Bean 的初始化过程,具体看代码吧!
package com.mmt.imitate.spring.framework.webmvc.servlet;import com.mmt.imitate.spring.framework.context.ApplicationContext;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Arrays;/** * 高仿 spring - mvc 入口类 ** 委派模式 * 职责:负责任务调度,请求分发 * */public class DispatcherServlet extends HttpServlet { private ApplicationContext applicationContext; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //TODO 委派,根据URL去找到一个对应的Method并通过response返回 try { doDispatch(req, resp); } catch (Exception e) { e.printStackTrace(); resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace())); } } /** * 通过 init方法来进行 ioc 容器的初始化动作 和 初始化 MVC 相关的 9 大组件 * * @param config * @throws ServletException */ @Override public void init(ServletConfig config) throws ServletException { // 初始化 IOC 相关 applicationContext = new ApplicationContext(config.getInitParameter("contextConfigLocation")); //TODO 初始化 MVC 部分,下次继续 } /** * mvc 响应 * * @param req * @param resp * @throws Exception */ private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { //TODO }}
注意 init 方法,在 init 方法中,进行了 IOC 容器的初始化以及 MVC 相关的初始化动作,这里需要完善一下 ApplicationContext 类:
package com.mmt.imitate.spring.framework.context;import com.mmt.imitate.spring.framework.annotation.MmtAutowired;import com.mmt.imitate.spring.framework.annotation.MmtController;import com.mmt.imitate.spring.framework.annotation.MmtService;import com.mmt.imitate.spring.framework.beans.BeanWrapper;import com.mmt.imitate.spring.framework.beans.config.BeanDefinition;import com.mmt.imitate.spring.framework.beans.support.BeanDefinitionReader;import java.lang.reflect.Field;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 完成 bean 的创建和 DI * */public class ApplicationContext { private BeanDefinitionReader reader; private MapbeanDefinitionMap = new HashMap (); private Map factoryBeanObjectCache = new HashMap (); private Map factoryBeanInstanceCache = new HashMap (); public ApplicationContext(String... configLocations) { //1、 加载配置文件 reader = new BeanDefinitionReader(configLocations); try { //2、解析配置文件,封装成BeanDefinition List beanDefinitions = reader.loadBeanDefinitions(); //3、把BeanDefintion缓存起来 doRegistBeanDefinition(beanDefinitions); //4、自动装配 doAutowrited(); } catch (Exception e) { e.printStackTrace(); } } private void doRegistBeanDefinition(List beanDefinitions) throws Exception { for (BeanDefinition beanDefinition : beanDefinitions) { if (this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) { throw new Exception("The " + beanDefinition.getFactoryBeanName() + "is exists"); } beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition); beanDefinitionMap.put(beanDefinition.getBeanClassName(), beanDefinition); } } /** * 自动装配 */ private void doAutowrited() { //调用getBean() //这一步,所有的Bean并没有真正的实例化,还只是配置阶段 for (Map.Entry beanDefinitionEntry : this.beanDefinitionMap.entrySet()) { String beanName = beanDefinitionEntry.getKey(); getBean(beanName); } } /** * Bean的实例化,DI是从而这个方法开始的 * * @param beanName * @return */ public Object getBean(String beanName) { //1、先拿到BeanDefinition配置信息 BeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName); //2、反射实例化newInstance(); Object instance = instantiateBean(beanName, beanDefinition); //3、封装成一个叫做BeanWrapper BeanWrapper beanWrapper = new BeanWrapper(instance); //4、保存到IoC容器 factoryBeanInstanceCache.put(beanName, beanWrapper); //5、执行依赖注入 populateBean(beanName, beanDefinition, beanWrapper); return beanWrapper.getWrapperInstance(); } /** * 创建真正的实例对象 * * @param beanName * @param beanDefinition * @return */ private Object instantiateBean(String beanName, BeanDefinition beanDefinition) { String className = beanDefinition.getBeanClassName(); Object instance = null; try { Class clazz = Class.forName(className); //2、默认的类名首字母小写 instance = clazz.newInstance(); this.factoryBeanObjectCache.put(beanName, instance); } catch (Exception e) { e.printStackTrace(); } return instance; } private void populateBean(String beanName, BeanDefinition beanDefinition, BeanWrapper beanWrapper) { //可能涉及到循环依赖? //A{ B b} //B{ A b} //用两个缓存,循环两次 //1、把第一次读取结果为空的BeanDefinition存到第一个缓存 //2、等第一次循环之后,第二次循环再检查第一次的缓存,再进行赋值 Object instance = beanWrapper.getWrapperInstance(); Class clazz = beanWrapper.getWrappedClass(); //在Spring中@Component,这里只是单纯的处理了 controller 和 service 两个注解 if (!(clazz.isAnnotationPresent(MmtController.class) || clazz.isAnnotationPresent(MmtService.class))) { return; } //把所有的包括private/protected/default/public 修饰字段都取出来 for (Field field : clazz.getDeclaredFields()) { if (!field.isAnnotationPresent(MmtAutowired.class)) { continue; } MmtAutowired autowired = field.getAnnotation(MmtAutowired.class); //如果用户没有自定义的beanName,就默认根据类型注入 String autowiredBeanName = autowired.value().trim(); if ("".equals(autowiredBeanName)) { //field.getType().getName() 获取字段的类型 autowiredBeanName = field.getType().getName(); } //暴力访问 field.setAccessible(true); try { if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) { continue; } //ioc.get(beanName) 相当于通过接口的全名拿到接口的实现的实例 field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance()); } catch (IllegalAccessException e) { e.printStackTrace(); continue; } } }}
由于代码太多,不一一贴于此处,如有需要源码的小伙伴,可到Gitee进行下载:
后续更新,初始化 SpringMVC 9大组件及使用。
转载地址:http://fupwwy.baihongyu.com/