大概思路

  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. Android的API版本和名称对应关系

    Android版本名和API Level关系全称 Android的版本 Android版本名称Code name Android的API level Android 1.0 (API level 1) ...

  2. 【转】Scheme 编程环境的设置

    Scheme 编程环境的设置 介绍了这么久的 Scheme,却没有讲过如何配置一个高效的 Scheme 的编程环境.有些人开始学习 Scheme 的时候感觉无从下手,所以今天讲一下它的配置. Sche ...

  3. Python 文件 seek() 方法

    概述 Python 文件 seek() 方法用于移动文件读取指针到指定位置. 语法 seek() 方法语法如下: fileObject.seek(offset[,whence]) 参数 offset  ...

  4. Android RoboGuice开源框架、Butter Knife开源框架浅析

    Google Guice on Android(RoboGuice) 今天介绍一下Google的这个开源框架RoboGuice, 它的作用跟之前讲过的Dagger框架差点儿是一样的,仅仅是Dagger ...

  5. 常用代码之五:RequireJS, 一个Define需要且只能有一个返回值/对象,一个JS文件里只能放一个Define.

    RequireJS 介绍说一个JS文件里只能放一个Define,这个众所周知,不提. 关于Define,它需要有一个返回值/对象,且只能有一个返回值/对象,这一点却是好多帖子没有提到的,但又非常重要的 ...

  6. JDK1.7新特性,语言篇

    1. 可以用二进制表达数字 可以用二进制表达数字(加前缀0b/0B),包括:byte, short, int, long // 可以用二进制表达数字(加前缀0b/0B),包括:byte, short, ...

  7. 解决 SQL Server 所有帐号无 sysadmin 权限,且未启用 SQL Server 身份验证,sa 帐号也未启用的问题

    解决 未启用 SQL Server 身份验证 的问题: 1. 运行 regedit,进入注册表编辑器 2. 打开:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Micro ...

  8. 在 Windows 7 中安装 .NET Framework 时遇到错误:无法建立到信任根颁发机构的证书链

    当全新安装 Windows 7 SP1 后,在未安装任何补丁,也未进行联网的状态下,安装 .NET Framework 4.6 或更高的版本时,应该会遇到错误提示:无法建立到信任根颁发机构的证书链. ...

  9. 用较早版本的APIs实现抽象类

    原文链接:http://android.eoe.cn/topic/android_sdk 用较早版本的APIs实现抽象类 这节课程我们讨论如何创建一个实现类,即能对应新版本的API,又能够保持对老版本 ...

  10. 在c/c++中浮点数是否为0的判断

    在c/c++中,因为浮点数在内存中的表示是不精确的,会有很微小的误差,所以判断是否为0,就看它的绝对值是不是<=eps. eps可以看成是epsilon的缩写,可以用来表示一个无穷小的量,通常取 ...