debug查看ioc容器结构

@Test
    public void getHero(){
        //创建一个容器,并和配置文件关联(一个容器关联一个配置文件)
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        //Object hero0 = ioc.getBean("hero01");//这样获取默认是object,但是编译类型还是Hero,可以强转一下
        Hero hero0 = (Hero) ioc.getBean("hero01");//这样获取默认是object,但是编译类型还是Hero,可以强转一下
        Hero hero01 = ioc.getBean("hero01", Hero.class);//这种方法制定了class类对象,所以不用转
    }

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--解读:
    1.beans.xml中可以配置多个bean(一个bean标签表示一个Java对象),这里配置一个hero对象的JavaBean
    2.class属性写类的全路径 => 用于spring底层反射创建对象
    3.<bean class="com.recorder.spring.bean.Hero" id="hero01">
    id表示该bean对象在spring容器中的id,可以通过id获取容器中的对象
    4.<property name="id" value="1"></property> value用于给对象的实行赋值
    -->
    <bean class="com.recorder.spring.bean.Hero" id="hero01">

        <property name="id" value="1"></property>
        <property name="name" value="李白"></property>
        <property name="skill" value="青莲剑歌"></property>

    </bean>

</beans>

这里的ioc是一个重量级的对象,创建比较耗费资源,一般创建一个就可以。

ioc下面的beanFactory就是bean工厂,下面的beanDefinitionMap(类型是ConcurrentHashMap)是一个比较重要的属性

它将我们在beans.xml文件中配置的各个bean的信息保存到了下面的table属性中(只是保留了定义信息,还没有创建成对象),

在debug中可以看到table是一个初始512大小(超过会自动扩容)的ConcurrentHashMap$Node的匿名内部类类型的数组,使用这个内部类是因为方便保存所需要的(对象)信息

不如我们先看一下这个内部类

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        volatile V val;
        volatile Node<K,V> next;

        Node(int hash, K key, V val, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.val = val;
            this.next = next;
        }

        public final K getKey()       { return key; }
        public final V getValue()     { return val; }
        public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
        public final String toString(){ return key + "=" + val; }
        public final V setValue(V value) {
            throw new UnsupportedOperationException();
        }

        public final boolean equals(Object o) {
            Object k, v, u; Map.Entry<?,?> e;
            return ((o instanceof Map.Entry) &&
                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
                    (v = e.getValue()) != null &&
                    (k == key || k.equals(key)) &&
                    (v == (u = val) || v.equals(u)));
        }

        /**
         * Virtualized support for map.get(); overridden in subclasses.
         */
        Node<K,V> find(int h, Object k) {
            Node<K,V> e = this;
            if (k != null) {
                do {
                    K ek;
                    if (e.hash == h &&
                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                } while ((e = e.next) != null);
            }
            return null;
        }
    }

 

 我们看一下在table中保存的bean信息

 

可以看到我们在xml文件中配置的各项属性

key就是我们在xml文件中配置的id,

val是GenericBeanDefinition类型的,保存的是配置的对象(hero01)的类(Hero)信息

懒加载就是在使用之前就创建好,非懒加载就是在使用的时候再动态创建

propertyValue就是对象类的各个属性的信息

 propertyValue中有一个elementData数组,里面的name就是xml中类的属性的名称,value就是xml中配置的值

 

 刚才看的是保存的类信息,那么容器中创建的对象在哪里呢

我们看到beanFactory中还有一个属性叫singletonObjects(一个单例对象池),创建的对象就在这里,类型依旧是上面看到的内部类

如果在xml中配置的对象是单例的,就会初始化放在table中

 

 我们看一下对象信息,可以看到是和内部类的结构对应的,因为不知道存储的对象类型,所以使用了泛型(V)

 

 当我们执行 ioc.getBean("hero01", Hero.class) 这个getBean方法的时候,会先通过传入的id去beanDefinitionMap中查看是不是一个单例的对象

如果是的话就直接返回这个对象,如果不是就通过反射机制动态地创建一个再返回

 

 

另外spring为了方便通过id快速查找,将id也存在了beanFactory下的beanDefinitionNames中,可以通过这个属性快速查看我们地xml中配置了多少个bean

 

 

示意图:

 

 

posted @ 2022-06-28 16:14  紫英626  阅读(69)  评论(0)    收藏  举报

紫英