大概思路

  1. 通过读取配置文件,获取框架要加载的包路径:base-package,类似于 Spring 配置文件中的:

    1. <context:component-scan base-package="*"/>
  2. 将 base-package 路径下的所有类都加载,并保存在一个 Set<Class<?>> classSet 中;
  3. 初始化 Bean 容器,遍历 classSet,通过反射获得 Class 的实例,并保存 Class 与 Class实例的映射关系,即 Map<Class<?>, Object> instanceMap;
  4. 初始化 Ioc,遍历 Bean 容器,找出有 @Controller 注解的 Class,遍历其成员变量,如果其成员变量有 @Inject 注解,则从 instanceMap 中获取对应的 Service 类,通过反射设置该 Bean 实例的成员变量;

思维导图

对比 Spring 框架

Spring 的设计理念:

Spring 的三个核心组件就是 Context、Core 和 Bean 组件。

  • Context 组件:就是一个 Bean 关系的集合,这个关系集合又叫做 Ioc 容器;
  • Core 组件:是集发现、建立和维护每个 Bean 之间关系所需的一系列工具类;
  • Bean 组件:包装 Bean 实例的 Object,Bean 由 BeanFactory 创建;

三者关系,如下图所示:

与 Spring 框架三大组件的对比:

Context 组件,对应,Ioc 容器(IocHelper 提供依赖注入功能);

Core 组件,对应,类加载器、反射工具类,建立和维护 Bean 之间关系的工具类;

Bean 组件,基本相同;

简单模拟 Ioc

模拟 Controller 类:

  1. package org.zhengbin.ioc.test;
  2.  
  3. /**
  4. * Created by zhengbinMac on 2017/4/10.
  5. */
  6. // 假设这是一个 Controller 类
  7. public class TestController {
  8.  
  9. // 假设这是一个待注入的 Service
  10. private String wordService;
  11.  
  12. // 假设这是一个 Action 方法,方法中有调用 Service 来实现具体的业务逻辑
  13. public void toOut() {
  14. System.out.println("Hello1 " + wordService);
  15. }
  16.  
  17. // 有入参的 Action 方法
  18. public void toOut(String str) {
  19. System.out.println("Hello2 " + str);
  20. }
  21. }

模拟 Ioc 注入管理:

  1. package org.zhengbin.ioc.test;
  2.  
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7.  
  8. /**
  9. * Created by zhengbinMac on 2017/4/10.
  10. */
  11. public class TempIoc {
  12. // Bean 容器,保存 Bean 类与 Bean 实例之间的映射关系
  13. private static Map<Class<?>, Object> BEAN_MAP = new HashMap<Class<?>, Object>();
  14.  
  15. public static void main(String[] args) {
  16. try {
  17. // 加载类实例
  18. Class<?> cla = getClazz("org.zhengbin.ioc.test.TestController");
  19. // 存入 BeanMap 中(即放入 Bean 容器中)
  20. Object instance = newInstance(cla);
  21. BEAN_MAP.put(cla, instance);
  22.  
  23. // 需要时(在初始化整个 Web 框架时),从 BEAN_MAP 中获取类与类实例(即 Bean 类与 Bean 实例)
  24. Object bean = BEAN_MAP.get(cla);
  25.  
  26. // 获取反射类的所有变量,getFields()是获取公开的变量
  27. Field[] fields = cla.getDeclaredFields();
  28. for (Field field : fields) {
  29. // 设置反射类 "实例" 的成员变量值
  30. setField(bean, field, "你好");
  31. }
  32.  
  33. // 获取 Bean 实例的所有方法
  34. Method[] methods = cla.getDeclaredMethods();
  35. for (Method method : methods) {
  36. // 模拟 Action 方法是否需要带入参数
  37. Class<?>[] classes = method.getParameterTypes();
  38. if (classes.length == 0) {
  39. // 调用方法
  40. invokeMethod(bean, method);
  41. } else {
  42. invokeMethod(bean, method, "你好");
  43. }
  44. }
  45. } catch (Exception e) {
  46. throw new RuntimeException(e);
  47. }
  48. }
  49.  
  50. /**
  51. * 加载类
  52. * @param packageName 类的全路径地址(包名.类名)
  53. * @return Bean 类
  54. */
  55. private static Class<?> getClazz(String packageName) {
  56. Class<?> cls;
  57. try {
  58. cls = Class.forName(packageName);
  59. } catch (Exception e) {
  60. throw new RuntimeException(e);
  61. }
  62. return cls;
  63. }
  64.  
  65. /**
  66. * 创建实例
  67. * @param cls Bean 类
  68. * @return Bean 类的实例
  69. */
  70. private static Object newInstance(Class<?> cls) {
  71. Object instance;
  72. try {
  73. instance = cls.newInstance();
  74. } catch (Exception e) {
  75. throw new RuntimeException(e);
  76. }
  77. return instance;
  78. }
  79.  
  80. /**
  81. * 设置成员变量值
  82. * @param obj Bean 实例
  83. * @param field 成员变量
  84. * @param value 成员变量的赋值
  85. */
  86. private static void setField(Object obj, Field field, Object value) {
  87. try {
  88. // 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
  89. // 值为 false 则指示反射的对象应该实施 Java 语言访问检查。
  90. field.setAccessible(true);
  91. field.set(obj, value);
  92. } catch (IllegalAccessException e) {
  93. e.printStackTrace();
  94. }
  95. }
  96.  
  97. /**
  98. * 调用方法
  99. * @param obj Bean 实例
  100. * @param method 方法(Controller 中的 Action 方法)
  101. * @param args 方法的入参
  102. * @return 方法返回值
  103. */
  104. private static Object invokeMethod(Object obj, Method method, Object... args) {
  105. Object result;
  106. try {
  107. method.setAccessible(true);
  108. result = method.invoke(obj, args);
  109. } catch (Exception e) {
  110. throw new RuntimeException(e);
  111. }
  112. return result;
  113. }
  114. }

输出结果:

  1. Hello1 你好
  2. Hello2 你好

从零写Java Web框架——实现Ioc依赖注入的更多相关文章

  1. 从零写Java Web框架——请求的处理DispatcherServlet

    大概思路 继承 HttpServlet,实现 DispatcherServlet,拦截所有请求: DispatchServlet 重写 init()方法,负责初始化框架: 重写 service()方法 ...

  2. 读《架构探险——从零开始写Java Web框架》

    内容提要 <架构探险--从零开始写Java Web框架>首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA.Maven.Git 等开发工具搭建 Java Web 应用:接着通 ...

  3. 【EatBook】-NO.3.EatBook.3.JavaArchitecture.2.001-《架构探险:从零开始写Java Web框架》-

    1.0.0 Summary Tittle:[EatBook]-NO.3.EatBook.3.JavaArchitecture.2.001-<架构探险:从零开始写Java Web框架>- S ...

  4. 手写web框架之实现依赖注入功能

    我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...

  5. Java Web系列:Spring依赖注入基础

    一.Spring简介 1.Spring简化Java开发 Spring Framework是一个应用框架,框架一般是半成品,我们在框架的基础上可以不用每个项目自己实现架构.基础设施和常用功能性组件,而是 ...

  6. 《架构探险——从零开始写Java Web框架》这书不错,能看懂的入门书

    这书适合我. 哈哈,结合 以前的知识点,勉强能看懂. 讲得细,还可以参照着弄出来. 希望能坚持 完成啦... 原来,JSTL就类似于DJANGO中的模板. 而servlet类中的res,req,玩了D ...

  7. 架构探险——从零开始写Java Web框架》第二章照作

    沉下来慢慢看实现了. 越来越觉得可以和DJANGO作对比. package org.smart4j.chapter2.model; /** * Created by sahara on 2016/3/ ...

  8. Smart Framework:轻量级 Java Web 框架

    Smart Framework:轻量级 Java Web 框架 收藏 黄勇   工作闲暇之余,我开发了一款轻量级 Java Web 框架 —— Smart Framework. 开发该框架是为了: 加 ...

  9. JAVA web 框架集合

    “框架”犹如滔滔江水连绵不绝, 知道有它就好,先掌握自己工作和主流的框架: 在研究好用和新框架. 主流框架教程分享在Java帮帮-免费资源网 其他教程需要时间制作,会陆续分享!!! 152款框架,你还 ...

随机推荐

  1. 基于matplotlib的数据可视化 - 饼状图pie

    绘制饼状图的基本语法 创建数组 x 的饼图,每个楔形的面积由 x / sum(x) 决定: 若 sum(x) < 1,则 x 数组不会被标准化,x 值即为楔形区域面积占比.注意,该种情况会出现 ...

  2. thinkphp __hash__

    thinkphp会自动在模板文件的表单后加一个__hash__来验证提交,保证一定程序上的安全: 但是有时用不着,可以用: C('TOKEN_ON',false); 关闭这项

  3. Docker 学习笔记 ---Docker组件

    Docker组件 1.  客户端:dockerclient 2.  服务端:dockerserver 3.  Docker镜像 4.  Registry 5.  Docker 容器 Docker客户端 ...

  4. GC那些事儿--Android内存优化第一弹

    引言 接App优化之内存优化(序), 作为App优化系列中内存优化的一个小部分. 由于内存相关知识比较生涩, 内存优化中使用到的相关工具, 也有很多专有名词. 对Java内存管理, GC, Andro ...

  5. ios标准开发者账号 ios企业开发者账号的区别总结

    ios标准开发者账号 ios企业开发者账号的区别总结   ios标准开发者项目 1.ios标准开发者项目账号可以发布到app store 2.ios标准开发者项目分为两种:①个人开发者②公司/机构开发 ...

  6. RGB 常用颜色对照表

    http://blog.csdn.net/xiaoting451292510/article/details/8226325

  7. java.lang.RuntimeException: Date pattern must be set for column update_time in the schema of component

    使用Talend open studio  ,从mysql数据源中读取数据,将数据导出到excel文档,另外一个mysql数据库,和一个普通文件,遇到标题的错误,模型如下图所示: tMap将30.7中 ...

  8. MySql(十):MySQL性能调优——MySQL Server性能优化

    本章主要通过针对MySQL Server( mysqld)相关实现机制的分析,得到一些相应的优化建议.主要涉及MySQL的安装以及相关参数设置的优化,但不包括mysqld之外的比如存储引擎相关的参数优 ...

  9. grub配置指南

    GRUB(统一引导装入器)是基本的Linux引导装入器.其有四个作用,如下:1.选择操作系统(如果计算机上安装了多个操作系统).2.表示相应引导文件所在的分区.3.找到内核.4.运行初始内存盘,设置内 ...

  10. Atitit 图像处理类库 halcon11  安装与环境搭建attilax总结

    Atitit 图像处理类库 halcon11  安装与环境搭建attilax总结 正常安装软件,安装前请先退出其它一切正在运行的程序. 先安装halcon-10.0-windows.exe.安装完成后 ...