大概思路

  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. [企业化NET]Window Server 2008 R2[1]-服务器基本安装即问题解决记录

    1.  服务器基本安装即问题解决记录      √ 2.  SVN环境搭建和客户端使用 2.1  服务端 和 客户端 安装    √ 2.2  项目建立与基本使用     √ 2.3  基本冲突解决, ...

  2. MVC摘记

    2013年9月23日18:04:06 直接cshtml页面的js中使用     var customerId = @(ViewBag.Oppotunity as OppotunityDto==null ...

  3. MySQL复制的管理和维护

    1.查看主库 mysql> show master status; mysql> show master status; +------------------+-----------+- ...

  4. SteveY对Amazon和Google平台的吐槽

    Steve Yegge, Amazon的前员工,现任Google员工,其本来想在Google+上和Google的员工讨论一些关于平台的东西,结果不小心把圈子设成了Public,结果这篇文章就公开给了全 ...

  5. 企业内知识库wiki所存在的问题

    相信很多公司都利用开源的wiki web app搭建了自家的内部wiki服务,比如使用media Wiki, Gollum, doku wiki, jsWiki等 但是,真正可用的企业wiki系统却没 ...

  6. SharePoint 2013 启用 以其他用户身份登陆(Sign in as different user)

    习惯于SharePoint 2010的用户会发现,SharePoint 2013默认把  以其他用户身份登陆(Sign in as different user)的选项去掉了,这对于开发人员来说很麻烦 ...

  7. Facade 设计模式

    目的 在一个子系统的一组接口上提供一个统一的接口.Facade 设计模式定义了一个更高级别的接口,使子系统更容易使用. 通过一个更加简洁的接口来包装一个复杂的子系统. 解决的问题 客户端需要一个简化的 ...

  8. 【蓝桥杯】PREV-21 回文数字

    题目链接:http://lx.lanqiao.org/problem.page? gpid=T113   历届试题 回文数字   时间限制:1.0s   内存限制:256.0MB      问题描写叙 ...

  9. jmeter maven自动移动jar包windows 批处理命令

    jmeter项目maven文件下面放这.bat 工具,可以把必要的jar包移动到jmeter响应的文件夹下面 rem 本文件放在jmeter 脚本maven项目根目录下面,和pom.xml在同一个文件 ...

  10. 前端表单中有按钮button自动提交表单

    问题描述 在设计表单时,表单内有一个按钮<button>,该按钮是用来获取其他数据或执行其他操作的.并不是让他提交表单. 解决方案 1) 设置 form 的 onsubmit='retur ...