IOC的概念
首先我们要理解IOC。控制反转?那么他跟我们常说得DI是什么关系?IOC是一种思想。不限于语言。不限于框架。spring是IOC的一个实现而已。而所谓的DI依赖注入。就是实现控制反转这种思想的一种方式。
bean定义的理解
spring可以看作是一个IOC容器。容器。用来放东西的。我们思考。放东西。然后交给容器来管理,是不是需要容器理解我们放的东西呢?容器怎么理解。你放的对象千奇百怪。所以容器将其封装为一种数据结构。就是大名鼎鼎的beanDefinition,bean定义对象。用来描述我们的对象。使得容器理解解析。
创建容器
新建一个容器,这个容器是基于注解的。大家可以看一下,是不是与springboot的启动类有点像呢?如果将MainConfig类比成当前类。这个就是基于注解的容器的创建。
AnnotationConfigApplicationContext ctx =new AnnotationConfigApplicationContext(MainConfig.class);
进行debug
首先会进去一个静态代码块,这里先不关注。
然后进去了构造方法。这里我们传入了一个配置类作为参数,其实是可以传入多个的配置类。这个构造函数是一个可变参数。总共三个方法。this();register(componentClasses);
refresh();
this方法解析
这个是无参构造。这里我们的容器继承了GenericApplicationContext,而且没有显式调用父类构造方法,所以会调用父类默认构造方法。
这里我们要说一下。ApplicationContext理解为应用上下文。它是容器的高级应用形式。顶层父类也是beanFactory。在这里我们可以看到。GenericApplicationContext内部持有了一个基本的beanFactory。其实你可以这么理解。 GenericApplicationContext以及DefaultListableBeanFactory他们最初都是容器。但是为了不同的用处。他们在各自的道路上渐行渐远。ApplicationContext开始对环境,系统的一些东西越发强大,而DefaultListableBeanFactory则在容器的道路上越来越精。而ApplicationContext需要使用容器进行存储。自己又不关心这方面。怎么办??所以,拿到一个高级容器的引用。让来做容器。只付责调用就好了。DefaultListableBeanFactory这里有人可能会问?为什么new这个DefaultListableBeanFactory而不是其他的。很简单的道理。你有了意大利炮,还会用火炮吗???别问,好用就对了。执行完这个。就是内部持有的工厂进行了赋值。
当这句初始化执行完成以后,注解。我们的beanFactory里面的大多属性是null的,而beanDefinitionMap的大小是0。但是这里有个重点是。根据这个map的名称,这是一个用来防止bean定义的map。还没有初始化。你的bean。相当于一个鸡蛋,这是放鸡蛋的篮子。记住,不是放鸡的篮子。
this.reader =new AnnotatedBeanDefinitionReader(this);
在这里面做了一些事,根据名字可以看出,这是一个基于注解的bean定义的读取器,我们可以思考,既然是一个容器。我们需要向容器中放东西。由谁来放呢?就是这个对象。面向对象的思路告诉我们。谁来放知道了。还需要知道放去哪里。对不对呢?所以将这个对象作为参数,传进去。其实就是。我们需要一些工具以及方法。将对象转化为beanDefinition。这些系统自带的东西,应该早于我们的对象已经存在。
经过一系列调用,最核心的方法在这里。
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
第一次,给我们的beanFactory设置了两个组件。第一个应该是排序用的,第二个应该是条件注入的解析器。
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
向下走的逻辑就是就是一致的了,新建了一个集合。判断工厂中是否含有某个beanDefinition。
如果没有。就手动创建一个,添加到集合中。
其中第一个。很重要。我们可以看一下
然后继续向下走
this.scanner =new ClassPathBeanDefinitionScanner(this);
在我们配置包扫描时候。可以设置此属性。没设置默认为true。进入逻辑。
核心逻辑是将向包含过滤器中添加Component组件。
随着这个逻辑结束。我们的无参构造器的逻辑就结束了。我们完成了一个没有任何组件添加的容器的初始化。
register()方法解析
register(componentClasses) 首先我们观察,它的参数,是我们手写的配置类。接受可变参数、
debug进去
发现调用了一个do开头的方法,这也是spring的一个小特定。干活的,大多会以do开头
这个方法就是判断一些条件,设置好beanDefinition得一些属性,调用注册方法
注册方法核心代码
到这里一系列方法退出后,注册方法完成,这时候。查看,beanDefinitionMap里多了我们配置类得那个
小结
本文总计了容器的创建,容器中的beanFactory创建,以及一些系统内部的beanDefinition的创建,放置到map中的过程