spring是掌握java技能的基础,掌握了spring技术,就等于拿下了java的半壁江山。
我们以spring framework 5.3.10版本来探讨注解模式下的技术框架
spring其实就像一个工厂,每一次程序启动到结束,就是工厂成立到破产的过程,这是一个生产bean的工厂,在这里我们把bean理解为智能机器人。工厂一般都是各个部门协同合作,一般的步骤就是采购部门先采购原材料,加工部门把原材料进行初步加工,生产部门负责最终生产成品。
那么工厂成立,第一不要做的就是盖工厂,创建部门设施,我们今天就先从源码角度看下这个过程
spring启动就是下面这一行代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
再进一步看下源码
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
进入this方法:
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
以上就是spring启动的整个源码
我们来看下他们分别对应的角色:
AnnotationConfigApplicationContext是注解模式下spring启动的上下文,它就相当于那个工厂,所有的部门都隶属于这个工厂。
this.scanner 是扫描的意思,这个类负责根据配置的扫描路径进行扫描,充当是采购部门。
this.reader 是读取的意思,这个类是根据扫描到的类,读取类上的配置信息生成BeanDefinition对象,充当的是初加工部门。
此时我们看到了采购部门和加工部门,生产部门在哪里呢?
其实创办一个工厂,不仅仅是要这三个部门就足够了,肯定还需要其他的一些小的部门负责小的职能,比如保洁,后勤,车队,销售,运营等等。
我们不得不先来看看AnnotationConfigApplicationContext的类图
先来分析下spring这种模式,通过这张类图,不得不说spring充分运用了面向对象继承特性,对一些抽象类和接口的继承实现运用得当,这也是我在面向对象那一章把抽象类和接口归并在继承特性的原因,是的,面向对象基础就是很重要,再强的框架也是对基础的充分利用,同时,每个接口把功能独立出来,既是隔离又是单一职责,spring充分展现了面向接口编程的魅力。
看整个类图其实就是上层接口不断向下层接口归并功能的过程,最终由实现类完成功能填充:结合源码我们看一下关系
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver
EnvironmentCapable:提供获取运行时环境变量功能; MessageSource:提供国际化功能; ApplicationEventPublisher:提供事件机制功能; ResourcePatternResolver:提供加载资源功能; ListableBeanFactory和HierarchicalBeanFactory是BeanFacory的子类,BeanFacory在spring中成为bean工厂,但是在我们这个例子中我们称之为生产部门,这个接口有很多的子接口,孙子接口,这的ListableBeanFactory继承它,为它增加了bean实例批处理的功能,而HierarchicalBeanFactory继承它,为它增加了父容器的处理功能。
ApplicationContext接口继承了上面的所有接口,也就拥有了上面接口提供的所有功能;
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable
Lifecycle:提供了容器生命周期的相关功能 Closeable:提供了对资源关闭的功能
ConfigurableApplicationContext接口继承了上面的所有接口,也就拥有了ApplicationContext,Lifecycle,Closeable 接口提供的所有功能;
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext
DefaultResourceLoader类实现了ResourceLoader接口把接口功能填充完整,从而提供了资源加载的功能,和上面的ResourcePatternResolver接口不同,ResourcePatternResolver继承了ResourceLoader接口,只是对ResourceLoader接口的功能增加。
AbstractApplicationContext这个抽象类继承了DefaultResourceLoader,那么它就拥有了DefaultResourceLoader的功能,并且这些功能已经被实现,同时它又实现了ConfigurableApplicationContext,我们知道ConfigurableApplicationContext中融合了很多的接口功能,以为类实现实现接口就要实现接口中的所有方法,包括ResourcePatternResolver接口增强的的那一个方法。 AbstractApplicationContext是一个抽象类,它实现了所有接口的同时,它也有自己的抽象方法等待子类类实现。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
BeanDefinitionRegistry:提供了BeanDefinition相关操作的功能
GenericApplicationContext类继承了AbstractApplicationContext抽象类,实现了BeanDefinitionRegistry接口,这个具体类此时已经拥有了上面所有功能的具体实现。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry
AnnotationConfigRegistry:定义了扫描和注册的功能, AnnotationConfigApplicationContext最终继承了GenericApplicationContext类,并且实现了AnnotationConfigRegistry接口,从而一个完整的工厂形成了,已经完善了各种功能。
那么生产部门在哪里呢,我直接开门见山吧,
GenericApplicationContext类中有个DefaultListableBeanFactory类型的成员变量,这个类实际上也是BeanFactory家族的子子孙孙中的一个,那么这个属性是什么时候初始化的呢?我们可以看到在GenericApplicationContext类的构造方法中给这个属性赋了值,因为AnnotationConfigApplicationContext是GenericApplicationContext子类,所有AnnotationConfigApplicationContext实例化的时候会先一步调用父类的构造方法,从而初始化DefaultListableBeanFactory这个bean工厂。
首先这里采用组合方式,我们之前的文章说过能用组合就不用继承,这里比较有意思,beanFactory提供对bean操作的接口,由AnnotationConfigApplicationContext家族来实现,但是AnnotationConfigApplicationContext把实现又委托给beanFactory家族的子孙GenericApplicationContext来实现,这就是专人做专事,AnnotationConfigApplicationContext家族是统筹全局的,干活的还是得交给下面的部门。
实际上我们上面说的所有都是在讲this方法。
那么下面这两个方法是做什么呢? register(componentClasses); refresh();
实际上this方法完成后,这个工厂就已经创建完成。接下来就是到了真正干活的时候了,下面两个方法就开启了生产bean的整个过程。我们下回分解。
了解更多请关注微信公众号:码农本农