大概思路

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

    <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 类:

package org.zhengbin.ioc.test;

/**
* Created by zhengbinMac on 2017/4/10.
*/
// 假设这是一个 Controller 类
public class TestController { // 假设这是一个待注入的 Service
private String wordService; // 假设这是一个 Action 方法,方法中有调用 Service 来实现具体的业务逻辑
public void toOut() {
System.out.println("Hello1 " + wordService);
} // 有入参的 Action 方法
public void toOut(String str) {
System.out.println("Hello2 " + str);
}
}

模拟 Ioc 注入管理:

package org.zhengbin.ioc.test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; /**
* Created by zhengbinMac on 2017/4/10.
*/
public class TempIoc {
// Bean 容器,保存 Bean 类与 Bean 实例之间的映射关系
private static Map<Class<?>, Object> BEAN_MAP = new HashMap<Class<?>, Object>(); public static void main(String[] args) {
try {
// 加载类实例
Class<?> cla = getClazz("org.zhengbin.ioc.test.TestController");
// 存入 BeanMap 中(即放入 Bean 容器中)
Object instance = newInstance(cla);
BEAN_MAP.put(cla, instance); // 需要时(在初始化整个 Web 框架时),从 BEAN_MAP 中获取类与类实例(即 Bean 类与 Bean 实例)
Object bean = BEAN_MAP.get(cla); // 获取反射类的所有变量,getFields()是获取公开的变量
Field[] fields = cla.getDeclaredFields();
for (Field field : fields) {
// 设置反射类 "实例" 的成员变量值
setField(bean, field, "你好");
} // 获取 Bean 实例的所有方法
Method[] methods = cla.getDeclaredMethods();
for (Method method : methods) {
// 模拟 Action 方法是否需要带入参数
Class<?>[] classes = method.getParameterTypes();
if (classes.length == 0) {
// 调用方法
invokeMethod(bean, method);
} else {
invokeMethod(bean, method, "你好");
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 加载类
* @param packageName 类的全路径地址(包名.类名)
* @return Bean 类
*/
private static Class<?> getClazz(String packageName) {
Class<?> cls;
try {
cls = Class.forName(packageName);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cls;
} /**
* 创建实例
* @param cls Bean 类
* @return Bean 类的实例
*/
private static Object newInstance(Class<?> cls) {
Object instance;
try {
instance = cls.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return instance;
} /**
* 设置成员变量值
* @param obj Bean 实例
* @param field 成员变量
* @param value 成员变量的赋值
*/
private static void setField(Object obj, Field field, Object value) {
try {
// 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
// 值为 false 则指示反射的对象应该实施 Java 语言访问检查。
field.setAccessible(true);
field.set(obj, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} /**
* 调用方法
* @param obj Bean 实例
* @param method 方法(Controller 中的 Action 方法)
* @param args 方法的入参
* @return 方法返回值
*/
private static Object invokeMethod(Object obj, Method method, Object... args) {
Object result;
try {
method.setAccessible(true);
result = method.invoke(obj, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}

输出结果:

Hello1 你好
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. svn开发常用整理

    1.删除tortoise svn中的账号信息 其实tortoise svn也是将账号信息存放在本地的配置文件中 在不同的操作系统下,操作基本类似,首先我们来看一下windows下如何操作的. 以win ...

  2. 数字的可视化:python画图之散点图sactter函数详解

    最近开始学习python编程,遇到scatter函数,感觉里面的参数不知道什么意思于是查资料,最后总结如下: 1.scatter函数原型 2.其中散点的形状参数marker如下: 3.其中颜色参数c如 ...

  3. Python 文件 next() 方法

    描述 Python 3 中的 文件 对象不支持 next() 方法. Python 3 的内置函数 next() 通过迭代器调用 __next__() 方法返回下一项. 在循环中,next()方法会在 ...

  4. sqlserver使用存储过程发送http请求

    本文主要向大家介绍了SQLServer数据库访问发送Http请求,通过具体的内容向大家展现,希望对大家学习SQLServer数据库有所帮助. -- 通用读取获取数据存储过程 --开启Sql Serve ...

  5. postman 定义并使用全局变量

    第一步:找到并打开右上角的设置图案  第二步,点击“Global” 按钮 第三步.如图所示,定义全局变量,然后点击“save”即可 第四步:如何使用全局变量,只需要 {{ key }} 即可,如图所示 ...

  6. 转 部署Zipkin分布式性能追踪日志系统的操作记录

    2017年02月27日 11:01:29 https://blog.csdn.net/konglongaa/article/details/58016398 阅读数:7631 Zipkin是Twitt ...

  7. 设计模式-装饰模式(Decorator Pattern)

    装饰模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活

  8. Atitit 路径规划法attilax总结 扫描线路法

    Atitit 路径规划法attilax总结 扫描线路法 2017/2/8 20:43:37[吐槽]深圳-小 2017/2/8 20:43:37 群主做什么的2017/2/10 10:03:15系统消  ...

  9. CentOS7静态IP设置

    [root@localhost network-scripts]# pwd /etc/sysconfig/network-scripts [root@localhost network-scripts ...

  10. FPM打包工具 可以把源码包制定为rpm包 是自动化部署的环节

    注意部FPM时的环境一定要跟生产环境的系统版本最好是保持一至,我第一次测试没通过,(我在CENTOS7和部属FPM打好的包在Centos6.x和安装,结果失败) 1:安装 FPM打包工具的依赖包: [ ...