Java Web 基础篇 L3 IOC,DI,简单模拟IOC容器

1 IOC

IOC(控制反转)即获得对象的方式由程序员主动创建,变成了从容器中获取对象,IOC是一种思想

IOC的目的就是为了让第三方创建对象(通过XML文件,注解等),需要用的时候再获取,让程序员更专注于业务逻辑

1.1 为什么使用IOC思想

考虑如下的应用场景,Dao层负责访问数据库,整个业务中存在三种数据库,分别是MySQL,Oracle,SQLServer,Service层被App层调用,且负责沟通Dao层获取数据
在这里插入图片描述
在这里插入图片描述
上述的写法能够在默认情况下,让用户从MySQL中获取数据,但是在AppService类中,默认创建了MySqlDao的对象,这就是问题所在,如果用户的需求发生了更改,不再使用MySQL,而是其它数据库,且整个工程非常庞大,类似AppService中默认创建的对象都需要进行重新替换,无疑是增加了开发难度,且随着用户需求的改变,而去改变框架内的代码,是绝对错误的

考虑如下的实现方式:
在这里插入图片描述
通过在AppService中增加一个set方法,来让用户使用,就避免了在框架内创建对象,由主动的创建对象,变成了被动的接收对象,这就是IOC,即控制反转,不再去new对象,而是在需要的时候去取对象,这样在上述的示例中,程序员就可以将更多精力放在Dao层,业务逻辑的处理上

1.2 IOC容器

1,读取XML配置文件或根据注解等,将生成的对象装入容器
2,使用时通过getBean("id")来获取对象

IOC思想在Spring中的体现就是IOC容器,写好配置后,Spring会根据配置实例化对象,将这些对象存入容器中,当需要使用对象时,不用手动的new一个,而是从容器中根据对象名取出已经配置完整的对象来使用

IOC容器就像商场,需要什么商品自己去找就好,而不用自己制作,原先创建对象new的过程就类似于自己制作一个商品

2 DI

DI 依赖注入即实现IOC思想的手段,构建IOC容器的具体方式

依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性由容器来注入

2.1 依赖注入的本质是反射机制

DI就是生成完整对象的过程,就是通过配置中对象的类得到Class对象,通过反射机制,由构造器或者set方法产生完整对象存入容器的过程

/**
 * @author 雫
 * @date 2021/2/21 - 14:59
 * @function POJO
 */
public class Point0 {
    
    
    private int row;
    private int col;

    public Point0() {
    
    }

    public Point0(int row, int col) {
    
    
        this.row = row;
        this.col = col;
    }

    public int getRow() {
    
    
        return row;
    }

    public void setRow(int row) {
    
    
        this.row = row;
    }

    public int getCol() {
    
    
        return col;
    }

    public void setCol(int col) {
    
    
        this.col = col;
    }

    @Override
    public String toString() {
    
    
        return "row:" + row + ", col:" + col;
    }
}

对于上面的POJO,如何在不通过new的方式创建一个完整的对象?

反射机制,获取Class对象,通过newInstance()方法生成空对象,找到每个成员的set方法,反射调用所有有效成员的set方法,就成功得到了一个完整的POJO对象

3 简单模拟IOC容器

3.1 BeanFactory

XML文件示例:
在这里插入图片描述
解析XML文件,通过获取Class对象使用newInstance()方法建立空对象,找到每个成员的set方法并执行,得到完整的对象,建立Map类型的beanPool,其键为String类型的对象名,值为完整对象

/**
 * @author 雫
 * @date 2021/2/21 - 15:51
 * @function 模拟IOC容器
 */
public class BeanFactory1 {
    
    
    private static final Map<String, Object> beanPool;

    static {
    
    
        beanPool = new HashMap<>();
    }

    @SuppressWarnings("all")
    public static void scan(String xmlPath) throws Throwable {
    
    
        new AbstractXMLParser() {
    
    
            @Override
            public void dealElement(Element element, int i) throws Throwable {
    
    
                String beanName = element.getAttribute("id");
                Class<?> klass = Class.forName(element.getAttribute("class"));

                Object bean = klass.newInstance();
                beanPool.put(beanName, bean);

                new AbstractXMLParser() {
    
    
                    @Override
                    public void dealElement(Element element, int i) throws Throwable {
    
    
                        String propertyName = element.getAttribute("name");
                        String strPropertyValue = element.getAttribute("value");

                        Field field = klass.getDeclaredField(propertyName);
                        Class<?> realPropertyType = field.getType();
                        String setterName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);

                        Method setMethod = klass.getDeclaredMethod(setterName, realPropertyType);
                        Object propertyValue = TypeParser.getValue(realPropertyType.toString(), strPropertyValue);
                        setMethod.invoke(bean, propertyValue);
                    }
                }.parseTag(element, "property");

                new AbstractXMLParser() {
    
    
                    @Override
                    public void dealElement(Element element, int i) throws Throwable {
    
    
                        String refName = element.getAttribute("name");
                        Class<?> refKlass = Class.forName(element.getAttribute("ref"));

                        Object refObject = refKlass.newInstance();

                        new AbstractXMLParser() {
    
    
                            @Override
                            public void dealElement(Element element, int i) throws Throwable {
    
    
                                String refPropertyName = element.getAttribute("name");
                                String refStrPropertyValue = element.getAttribute("value");

                                Field field = refKlass.getDeclaredField(refPropertyName);
                                Class<?> refRealPropertyType = field.getType();
                                String refSetterName = "set" + refPropertyName.substring(0, 1).toUpperCase() + refPropertyName.substring(1);

                                Method refSetMethod = refKlass.getDeclaredMethod(refSetterName, refRealPropertyType);
                                Object refPropertyValue = TypeParser.getValue(refRealPropertyType.toString(), refStrPropertyValue);
                                refSetMethod.invoke(refObject, refPropertyValue);

                                String klassSetRefMethodName = "set" + refName.substring(0, 1).toUpperCase() + refName.substring(1);
                                Method klassSetRefMethod = klass.getDeclaredMethod(klassSetRefMethodName, refKlass);
                                klassSetRefMethod.invoke(bean, refObject);
                            }
                        }.parseTag(element, "refProperty");

                    }
                }.parseTag(element, "rProperty");

            }
        }.parseTag(AbstractXMLParser.getOneDocument(xmlPath), "bean");
    }

    public static List<String> getKeys() {
    
    
        List<String> keys = new ArrayList<>();
        for(String key : beanPool.keySet()) {
    
    
            keys.add(key);
        }
        return keys;
    }

    public static Object getObject(String key) {
    
    
        return beanPool.get(key);
    }

}

3.2 测试&总结

测试:
在这里插入图片描述
总结:
1,解析XML文件时存在缺陷,必须按照成员类型的指定顺序进行配置,且过于简单,只能支持成员为八大基本类型和对象的配置
2,无法解决循环依赖,且生成IOC容器的过程采用的是饿汉模式,无法面对复杂问题,生成对象的过程与程序上下文脱节

猜你喜欢

转载自blog.csdn.net/weixin_43541094/article/details/113920174
今日推荐