依赖注入DI --- 二
大概思路:
已经实现了将所有的类初始化的过程, 接下来我们将类里使用了注解需要依赖注入的内容实现.
如Spring框架里, Controller类里面会依赖注入Service类, Service类里会依赖注入Dao类.
public class Controller1 { // 写一个简易的Controller类, 里面需要注入一个Service类 private static Service1 service1; public static void hello() { service1.sayHello(); } }
public class Servcie1Impl implements Service1{ // 这是Service @Override public void sayHello () { System.out.println("hello world"); } }
@Target(ElementType.FIELD) // 自定义一个注解 @Retention(RetentionPolicy.RUNTIME) public @interface Inject { Class<?> value(); }
接下来, 修改controller类里的内容, 为需要注入的service加上注解, 并写一个main主函数, 用来进行测试
public class Controller1 { @Inject(value = Servcie1Impl.class) private static Service1 service1; public static void hello() { service1.sayHello(); } public static void main(String[] args) { hello(); } }
我们最终想要得到的结果: 运行主方法, 可以打印出 hello world.
在这里, 我们可以运用上一章所产生的ClassUtil, 将所有的类进行创建, 然后我们把这些类放入模块上下文中
public class ModuleContext { private static final Set<Class<?>> BEAN_SET = new HashSet<>(); public static Set<Class<?>> getBeanSet () { // 定义一个getter方法 return BEAN_SET; } static { String basePackage = "myTest"; // 包名 BEAN_SET.addAll(ClassUtil.getClassSet(basePackage)); // ClassUtil: 上一章生成的 } }
在主方法中, 调用classutil的loadClass方法,
ClassUtil.loadClass(ModuleContext.class.getName(), false);
就把模块上下文初始化成功了.
接下来, 进行依赖注入
我们知道, controller里需要依赖注入service, 而service里需要依赖注入controller...., 所有, 需要进行递归操作, 每一次依赖注入的类都需要被依赖注入. 依赖注入是通过反射进行的, 定义一个反射工具类 ReflectUtil
在ReflectUtil里, 定义一个方法, 用来获取 属性Field上含有注解的注解的内容
public static <T>Map<Field, Map<String, T>> getAnnotatedFieldValue(Class<?> cls, Class<? extends Annotation> annotationCls) { Map<Field, Map<String, T>> rows = new HashMap<>(); for(Field field : cls.getDeclaredFields()) { if(field.isAnnotationPresent(annotationCls)) { Annotation annotation = field.getAnnotation(annotationCls); for(Method method : annotation.annotationType().getDeclaredMethods()) { if(rows.get(field) == null) { Map<String, T> value = new HashMap<>(); try { value.put(method.getName(), (T) method.invoke(annotation)); rows.put(field, value); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } }else { try { rows.get(field).put(method.getName(), (T) method.invoke(annotation)); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } } } } return rows; }rows里就装入了注解里面的内容
接下来, 定义一个方法用来进行属性的注入
public static void injectField(Object bean, Field target, Object value) { try { target.setAccessible(true); target.set(bean, value); } catch (IllegalAccessException e) { e.printStackTrace(); } }
这时呢, 需要区分一**入的是否是一个接口或其他的类型不匹配, 添加一个判断类
private static boolean isImplementOf (Class<?> impl, Class<?> inter) { for(Class<?> interfaces : impl.getInterfaces()) { if(interfaces == inter) { return true; } } return false; }
修改一下injectField类
public static void injectField(Object bean, Field target, Object value) { if(target.getType() == bean.getClass() && isImplementOf(bean.getClass(), target.getType())) { throw new RuntimeException("[ERROR] Field Type Do Not Match"); } try { target.setAccessible(true); target.set(bean, value); } catch (IllegalAccessException e) { e.printStackTrace(); } }
接下来, 在ModuleContext中定义一个方法, 再定义一个管理bean的类 BeanManager
ModuleContext:
public static <T> T getBean(Class<?> cls){ Object bean = null; if(BEAN_SET.contains(cls)){ for (Class<?> aClass : BEAN_SET) { if (aClass == cls) { bean = ReflectUtil.newInstance(aClass); } } }else { throw new RuntimeException("[ERROR] CLASS NOT FOUND"); } BeanManager.assemble(bean); return (T)bean; }
将所有的反射活动都抽离到ReflectUtil里去,
public static Object newInstance(Class<?> cls){ Object newInstance; try { newInstance = cls.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException(e); } return newInstance; }
BeanManager:
public class BeanManager { public static void assemble(Object bean) { for(Map.Entry<Field, Map<String, Object>> fieldMapEntry : ReflectUtil.getAnnotatedFieldValue(bean.getClass(), Inject.class).entrySet()) { injectField(bean, fieldMapEntry); } } private static void injectField (Object bean, Map.Entry<Field, Map<String, Object>> fieldMapEntry) { Field target = fieldMapEntry.getKey(); // 这里递归调用 ReflectUtil.injectField(bean, target, ModuleContext.getBean((Class<?>) fieldMapEntry.getValue().get("value"))); } }
进行递归调用, 就可以避免有些地方未注入
最后, 我们修改一下controller的主方法,进行一下测试
public static void main(String[] args) { ClassUtil.loadClass(ModuleContext.class.getName(), false); ModuleContext.getBean(Controller1.class); hello(); }
最后运行结果: