手写Spring mvc框架 (二)

五、控制反转(IOC)和依赖注入(DI)
  1. 概念

    • 控制反转:将创建对象的控制权反转给了spring

    • 依赖注入:spring在创建对象的过程中,动态地将依赖对象注入到Bean组件

  2. 实现

    工厂模式-BeanFactory

    从BeanFactory中获取对象,没有就创建,依赖没有就创建依赖,对象一般默认单例模式

    递归创建依赖会遇到循环依赖问题:

    • 如果需要的依赖正处于创建状态,则发生了循环依赖(可用ConcurrentHashMap缓存对象来判断)
    • 处理:将那个依赖的初始状态对象注入,即那个依赖对象里的成员变量为null

    BeanFactory简易实现代码:

    public class BeanFactory {
        //一个类对应一个对象
        private static Map<Class<?>, Object> classToBean = new ConcurrentHashMap<>();
    
        public static Object getBean(Class<?> cls) {
            return classToBean.get(cls);
        }
    
        public static void initBean(List<Class<?>> classList) throws Exception {
            List<Class<?>> toCreate = new ArrayList<>(classList);
            while (toCreate.size() != 0) {
                int remainSize = toCreate.size();
                for (int i=0;i<toCreate.size();i++) {
                    if (finishCreate(toCreate.get(i))) {
                        toCreate.remove(i);
                    }
                }
                if (toCreate.size() == remainSize) {
                    //这里没有解决循环依赖
                    throw new Exception("cycle dependency!");
                }
            }
        }
    
        private static boolean finishCreate(Class<?> cls) throws IllegalAccessException, InstantiationException {
            if (!cls.isAnnotationPresent(Bean.class) && !cls.isAnnotationPresent(Controller.class)) {
                return true;
            }
    
            Object bean = cls.newInstance();
            for (Field field : cls.getDeclaredFields()) {
                if (field.isAnnotationPresent(AutoWired.class)) {
                    Class<?> fieldType = field.getType();
                    Object reliantBean = BeanFactory.getBean(fieldType);
                    if (reliantBean == null) {
                        return false;
                    }
                    field.setAccessible(true);
                    field.set(bean, reliantBean);
                }
            }
            classToBean.put(cls, bean);
            return true;
        }
    }
六、AOP

概念:弥补OOP的缺点,给每个函数前后留一个切面,可以实现业务代码和功能代码的分离

  • jdk代理

    被代理对象需要有个接口,jdk通过动态实现这个接口来实现代理

  • cgLib代理

    被代理对象没有接口怎么办?我们通过获取它的class字节码文件,创造一个继承它的子类,从而实现代理

posted @ 2019-06-22 23:27 hzhuan 阅读(...) 评论(...) 编辑 收藏