大概思路
- 通过读取配置文件,获取框架要加载的包路径:base-package,类似于 Spring 配置文件中的:
<context:component-scan base-package="*"/>
- 将 base-package 路径下的所有类都加载,并保存在一个 Set<Class<?>> classSet 中;
- 初始化 Bean 容器,遍历 classSet,通过反射获得 Class 的实例,并保存 Class 与 Class实例的映射关系,即 Map<Class<?>, Object> instanceMap;
- 初始化 Ioc,遍历 Bean 容器,找出有 @Controller 注解的 Class,遍历其成员变量,如果其成员变量有 @Inject 注解,则从 instanceMap 中获取对应的 Service 类,通过反射设置该 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); } 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 你好
时间: 2024-10-09 02:06:45