IOC/DI 学习笔记

**

IOC/DI(控制反转/依赖注入)学习笔记

**
常规编程对象由程序员自己通过构造方法得到的。ioc控制反转提供了一种新的思想,在程序开始执行时,由代码生成对象并进行集中管理。

  • 对象的生成
    通过反射机制调用构造方法生成对象。对象之间的依赖关系可以通过注入的方法进行处理。通过学习spring,得到以下方法:可以通过构造方法进行初始化;也可以先反射调用无参构造,通过遍历setter方法对其成员赋值;或者通过对成员加注解的方式完成等等。
    spring还提供了配置文件进行解析的方式。将类及所需要的信息和依赖关系等内容写入配置文件中,通过解析配置文件来完成注入。写配置文件虽然很麻烦,但是却可以让用户清楚类与类之间的关系等。

每个对象都是beanFactyory中管理的一个bean,spring有自己的一系列代码为这个bean形成一个beanName,并形成键值对放入map中管理,用户也可以给对象设置别名,spring会将解析出来的别名放入map中管理,通过别名也可以获得对象。spring提供了getBean(…)方法让用户获得对象。

下面记录我自己写的一些代码以及分析:
只实现了对成员加注解进行注入的方法。需要用到包扫描的技术,不是此处的重点。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//加在类上的注解,说明要将加注解的类交给beanFactory进行管理
public @interface Component {
//    name为bean的别名
    String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
//将方法的返回值作为一个Bean存入BeanFactory中
public @interface Bean {
    String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Autowired {
//    成员或参数可以是八大基本类型,也可以是bean
//		目前只实现到如果value不为空串,那成员只能是八大基本类型,否则不处理。
//		如果value为空串,就认为其是beanFactory中的一个bean
    String value() default "";
}

对象有两种scope:singleton(单例)和prototype(原型)
并且有两种加载模式:延迟加载(即懒汉模式) 在getBean()的时候进行初始化和非延迟加载(饿汉模式)
这里只实现简单的单例延迟加载。
以下是对bean的定义:

public class BeanDefinition implements IBeanDefinition {
    private Object object;
    private String beanName;
    private String scope;

    public BeanDefinition() {
    }

    public BeanDefinition(Object object) {
        this.object = object;
    }

    @Override
    public Object getObject() {
        return this.object;
    }

    @Override
    public void steObject(Object object) {
        this.object = object;
    }

    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    @Override
    public String getBeanName() {
        return this.beanName;
    }
}

定义benadefinition的持有者:
包含有beandefinition、类类型、beanName、代理对象和injection,injection用来判断是否已经被注入,这是处理循环依赖的一个办法,spring中设置了一个是否允许提前曝光的属性(earlyexposure)
这里有代理对象是可以不存在的,由于将IOC和AOP写在了一起,进行强行融合,所以beanFactory中管理的其实是代理对象。对于代理的使用在AOP学习笔记中写出。

- 关于循环依赖:

假设现在又三个类,Class A、Class B、Class C
A中需要一个成员B,B中需要一个成员C,C中需要一个成员A的情况,单例模式可以在A没有完成注入的情况下将
A的对象注入给C;但是对于原型模式,不能这么做,必须将对A生成的对象a1完全实例化之后才能使用,否则如果有其他线程需要使用A生成一个不同对象a2,然而a1并没有完成赋值,这里就会出现大问题。因此循环依赖只有单例模式才能解决,原型模式不能解决循环依赖。在测试的时候会测试循环依赖的情况,代码在最后粘出。

public class BeanDefinitionHolder <T> implements IBeanDefinitionHolder {
//    beanDefinition的持有者
    private BeanDefinition beanDefinition;
    private Class<?> beanClass;
    private String beanName;
    private T proxy;
    private volatile boolean injection;
//    TODO 别名数组,暂时不想做
    private List<String> alias;
//实例化beanDefiniyionHolder时必须传入BeanDefinition以及beanClass或者className
    public BeanDefinitionHolder(BeanDefinition beanDefinition, Class<?> beanClass) {
        this.beanDefinition = beanDefinition;
        this.beanClass = beanClass;
        this.beanName = beanClass.getName();
        this.injection = false;
        alias = new ArrayList<>();
    }

    public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
        this.beanDefinition = beanDefinition;
        this.beanName = beanName;
    }

    public Object getProxy() {
        return this.proxy;
    }

    public void setProxy(T proxy) {
        this.proxy = proxy;
    }

    @Override
    public Class<?> getBeanClass() {
        if(this.beanClass != null) {
            return this.beanClass;
        } else if(this.beanName != null) {
            try {
                return Class.forName(beanName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public String getBeanName() {
        if(this.beanName != null) {
            return this.beanName;
        } else {
            return this.beanClass.getName();
        }
    }

    @Override
    public Object getObject() {
        return this.beanDefinition.getObject();
    }

    @Override
    public boolean isInjection() {
        return this.injection;
    }

    @Override
    public void changeInjection() {
        this.injection = true;
    }

    @Override
    public String toString() {
        return "BeanDefinitionHolder{" +
                "beanName='" + beanName + '\'' +
                '}';
    }
}

接下来是Bean工厂,beanFactory中实现了对bean的管理。
Spring中定义了FactoryBean,用以区分普通的bean。

!!!这里理解的不是很清楚,大概的意思应该是在factoryBean中有getObject()方法,可以用来返回代理以及织入拦截器。(以后对源码阅读的更加深入后进行修改)

采用懒汉模式,因此在包扫描时,只是读入基本信息,对beanDefinitionHolder进行填充并存入beanDefinitionHolderMap中,在geBean()时,首先在beanMap中get(),如果返回值不为null,则返回结果;如果返回null,则在BeanDefinidionHolderMap中找对应的beanDefinitionHolder,如果返回值依然是null,则应该抛出异常;如果得到了对应的beanDefinitionHolder,则根据beanDefinitionHoler生成bean,并返回。

初始化时先从beanDefinitionHolder中得到基本信息,然后通过反射机制处理其带有注解的成员和方法,完成后返回对象。

public abstract class BeanFactory implements IBeanFactory {
    //    beanMap存储的全是代理
    private volatile static Map<String, Object> beanMap;
    //		aliasMap是别名以及beanName形成的键值对,代码中并没有进行处理
    private volatile static Map<String, String> aliasMap;
    private volatile static Map<String, BeanDefinitionHolder> beanDefinitionHolderMap;
    private final static Object object = new Object();
    private final static Object createBeanObject = new Object();

    static {
        beanMap = new ConcurrentHashMap<>();
        aliasMap = new ConcurrentHashMap<>();
        beanDefinitionHolderMap = new ConcurrentHashMap<>();
    }

    private <T> T cglProxy(BeanDefinitionHolder beanDefinitionHolder) {
        String beanName = beanDefinitionHolder.getBeanName();
        T proxy = (T) beanMap.get(beanName);
        if (proxy != null) {
            return proxy;
        }
        synchronized (object) {
            proxy = (T) beanMap.get(beanName);
            if (proxy == null) {
                ProxyBulider proxyBulider = new ProxyBulider(beanDefinitionHolder);
                proxy = (T) proxyBulider.getCGLProxy(beanDefinitionHolder);
            }
        }
        return (T) proxy;
    }

    private <T> T jdkProxy(BeanDefinitionHolder beanDefinitionHolder) {
        String beanName = beanDefinitionHolder.getBeanName();
        T proxy = (T) beanMap.get(beanName);
        if (proxy != null) {
            return proxy;
        }
        synchronized (object) {
            proxy = (T) beanMap.get(beanName);
            ProxyBulider proxyBulider = new ProxyBulider(beanDefinitionHolder);
            proxy = (T) proxyBulider.getJDKProxy(beanDefinitionHolder);
        }
        return proxy;
    }

    //  根据Spring的思路,如果该类实现了接口,则优先获取jdk代理
    private <T> T doCreateProxy(BeanDefinitionHolder beanDefinitionHolder, Class<?> klass) throws Exception {
        T proxy;
        if (klass.getInterfaces().length > 0) {
            proxy = cteateJDKProxy(beanDefinitionHolder);
        } else {
            proxy = createCGLProxy(beanDefinitionHolder);
        }
        beanDefinitionHolder.setProxy(proxy);
        beanDefinitionHolder.changeInjection();
        initBean(beanDefinitionHolder);
        beanMap.put(klass.getName(), proxy);
        return proxy;
    }

    private void initBean(BeanDefinitionHolder beanDefinitionHolder) throws Exception {
        Class<?> klass = beanDefinitionHolder.getBeanClass();
        Object object = beanDefinitionHolder.getObject();
        Field[] fields = klass.getDeclaredFields();
        for (Field field : fields) {
            autowiredInjectionField(object, field);
        }
        Method[] methods = klass.getDeclaredMethods();
        for (Method method : methods) {
            autowiredMethod(method, object);
        }
    }

    //  DI主要针对的是复杂类类型(用户自定义类类型等),因此要求注入八大基本类型时注解必须要写value属性
// 否则将不进行处理,需要抛出异常
//  如果不是八大基本类型,则默认为是BeanFactory中的一个bean,即注入的是代理
    private Object autowiredInjectionField(Object object, Field field) throws Exception {
        if (field.isAnnotationPresent(Autowired.class)) {
            Autowired autowired = field.getAnnotation(Autowired.class);
            Class<?> fieldClass = field.getType();
            Object fieldObject;
            if (fieldClass.isPrimitive()) {
                String value = autowired.value();
                if (value.length() <= 0) {
                    throw new PrimitiveMustHaveValueAttributeException("八大基本类型的成员或参数" +
                            field + "必须含有value属性");
                }
//            这里将String类型的value转换为对应的八大基本类型并注入
                fieldObject = BeanUtils.stringToPrimitive(value, fieldClass);
            } else {
//                首先从BeanMap中获取,如果取不到,意味着循环依赖,其依赖的bean的代理还没有获取到,则处理循环依赖
                fieldObject = getBean(fieldClass.getName());
            }
            field.setAccessible(true);
            field.set(object, fieldObject);
        }
        return object;
    }

    //  Method上加Bean注解的意思在该方法的返回值为BeanFactory中的一个Bean,在初始化类时执行
//  需要先注入成员,在执行方法,因为考虑的该方法中可能需要用到某些成员的值
//  方法执行完毕后要将其返回值加入到BeanMap中
//  自执行方法如果有参数,则每个参数都应该加上相应的注解,
//  否则无法对其参数进行赋值,应该抛出异常
//  并且参数的返回值类型不能为void,这里强行规定返回值类型也不能是八大基本类型
//  TODO 这里并不能处理多个方法返回值都相同的情况
    private Object autowiredMethod(Method method, Object object) throws BeanMethodReturnTypeIsErrorException {
        if (method.isAnnotationPresent(Bean.class)) {
            Bean bean = method.getAnnotation(Bean.class);
            String name = bean.name();
            Class<?> methodClass = method.getReturnType();
            if (methodClass.equals(void.class) || methodClass.isPrimitive() ||
                    method.getParameters().length > 0) {
                throw new BeanMethodReturnTypeIsErrorException("Method" + method + "返回值类型不能是"
                        + methodClass);
            }
//          先判断是否加载了BeanDefinition,如果没有,先加载
//          TODO 这里先不处理有参数的方法,是否处理以后视情况而定
            String beanName = methodClass.getName();
            beanMap.put(beanName, doAutowiredMethod(object, method));
            if (name.length() > 0) {
                aliasMap.put(name, beanName);
            }
        }
        return object;
    }

    private Object doAutowiredMethod(Object object, Method method) {
        try {
            return method.invoke(object);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }

    private Object doCreateBean(Object proxy, String beanName, BeanDefinitionHolder beanDefinitionHolder) throws Exception {
        proxy = beanMap.get(beanName);
        if (proxy == null) {
            synchronized (createBeanObject) {
                proxy = beanMap.get(beanName);
                if (proxy == null) {
//                    通过injection来判断该Bean是否正在创建中,以此来解决循环依赖
                    if (!beanDefinitionHolder.isInjection()) {
                        proxy = createBean(beanDefinitionHolder);
                        return proxy;
                    } else {
                        return beanDefinitionHolder.getObject();
                    }
                }
            }
        }
        return proxy;
    }

    //    如果进行到这一步,获取的一定是代理
    @Override
    public <T> T createBean(BeanDefinitionHolder beanDefinitionHolder) throws Exception {
        Class<?> beanClass = beanDefinitionHolder.getBeanClass();
        return doCreateProxy(beanDefinitionHolder, beanClass);
    }

    @Override
    public <T> T createCGLProxy(BeanDefinitionHolder beanDefinitionHolder) {
        return cglProxy(beanDefinitionHolder);
    }

    @Override
    public <T> T cteateJDKProxy(BeanDefinitionHolder beanDefinitionHolder) {
        return jdkProxy(beanDefinitionHolder);
    }

    @Override
    public void setBeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
        if (!beanDefinitionHolderMap.containsValue(beanDefinitionHolder)) {
            beanDefinitionHolderMap.put(beanDefinitionHolder.getBeanName(), beanDefinitionHolder);
        }
    }

    @Override
    public BeanDefinitionHolder getBeanDefinitionHolder(String beanName) {
        return beanDefinitionHolderMap.get(beanName);
    }

    //    创建bean时需要考虑到循环依赖的情况,这里是通过对其成员进行注入解决的
//    TODO 以后还应该提供构造函数参数解析的方法
    @Override
    public <T> T getBean(String name) throws Exception {
        String beanName = name;
//    首先从beanMap中获取,因为有可能是扫描时某个方法的返回值,也有可能是某个已经被加载的bean
        Object proxy = beanMap.get(beanName);
        if (proxy != null) {
            return (T) proxy;
        }
//    如果获取不到,则找beanDefinitionHolder准备初始化bean
        BeanDefinitionHolder beanDefinitionHolder = beanDefinitionHolderMap.get(beanName);
        if (beanDefinitionHolder == null) {
            beanName = aliasMap.get(beanName);
            if (beanName == null) {
                beanName = name;
            }
            beanDefinitionHolder = beanDefinitionHolderMap.get(beanName);
        }
//    如果beanDefinitionHolder == null,则应该抛出异常
        if (beanDefinitionHolder == null) {
            throw new BeanDefinitionHolderIsNotExistException("未扫描到相关的Bean");
        }
        proxy = doCreateBean(proxy, beanName, beanDefinitionHolder);
        return (T) proxy;
    }

    void addAlias(String beanName, String alias) {
       aliasMap.put(beanName, alias);
    }

    public abstract void addBeanDefinitionholder(Class<?> klass);
}

默认bean工厂,执行包扫描以及beanDefinitionHolder的初始化形成beanDefinitionHolderMap,并提供getBean()的方法。
下面的代码给出getProxy()和getObject()方法用来实现getBean的功能。
spring中对bean工厂有更加详细的划分,这里不做出模仿。

public class DefaultBeanFactory extends BeanFactory implements IBeanBuilder {

    public void packageScan(String packagePath) {
        new PackageScanner() {

            @Override
            public void dealClass(Class<?> klass) {
                dealKlass(klass);
            }

        }.packageScanner(packagePath);
    }

    private void dealKlass(Class<?> klass) {
        if(!klass.isAnnotationPresent(Component.class)) {
            return;
        }
        Component component = klass.getAnnotation(Component.class);
        String alias = component.name();
//      为了方便初始化,这里统一使用无参构造,对于初始化时需要传入的参数等,使用对成员进行注入的方法
//      这里先进行包扫描形成对应的beanDefinitionMap,为以后getBean时取得Bean的所有信息打好基础
//      Spring中对于BeanDefinition的定义复杂,这里做的是极为简陋的
//       直接使用无参构造及逆行初始化
//       TODO 全部采取懒汉模式所以这里不用进行实例化操作,以后应该加上饿汉模式,拦截器是通过相关的代理加上的,
//       在形成代理时是否已经有了相应的拦截器链并不重要,但是在程序启动之前必须对拦截器类进行扫描
        addBeanDefinitionholder(klass);
        if(alias.length() > 0) {
            addAlias(klass.getName(), alias);
        }
    }

    @Override
    public Object getObject(Class<?> klass) {
        return getBeanDefinitionHolder(klass.getName()).getObject();
    }

    @Override
    public <T> T getproxy(Class<?> klass) {
        try {
            return getBean(klass.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void addBeanDefinitionholder(Class<?> klass) {
        BeanDefinition beanDefinition = new BeanDefinition();
        try {
            Object object = klass.newInstance();
            beanDefinition.steObject(object);
            beanDefinition.setBeanName(klass.getName());
            BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, klass);
            setBeanDefinitionHolder(beanDefinitionHolder);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

  • 测试:
@Component
public class A {
    @Autowired
    private B b;

    public A() {
    }

    public void setB(B b) {
        this.b = b;
    }

    public B getB() {
        return b;
    }

    public void fun(B b) throws Exception {
//        System.out.println("自动注入的num:" + this.num);

        System.out.println("这是fun方法");
        throw new Exception();
    }

    @Override
    public String toString() {
        return "这是A - >B\n" + b;
    }
}
@Component
public class C {
    @Autowired
    private A a;

    public C() {
    }

    public void setA(A a) {
        this.a = a;
    }

    public A getA() {
        return a;
    }

    public void fun() {

    }

    @Override
    public String toString() {
        return "这是C - >A";
    }
}
public class Demo {
    public static void main(String[] args) {
        DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory();
        defaultBeanFactory.packageScan("com.xxy.test");
        B b = new B();
        b.setNum(0);
        A a = defaultBeanFactory.getproxy(A.class);
        System.out.println(a);
    }
}

结果:
这是A - >B
这是B - >C
这是C - >A

Process finished with exit code 0

这是在学习了ioc之后做出的一些尝试性练习,如果有错误的地方还请各位大佬给予指正,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值