Spring框架,英文Spring Framework。何为框架?我们说Spring框架、Netty框架、Dubbo框架,其实框架就是一个半成品,它将相关领域的流程规范实现好了,但是只有框架是没有业务意义的,需要我们程序员往里面填充业务逻辑(业务逻辑体现在一个个Java的对象中),这样才能完整地实现一个业务系统。
Spring框架主要用于解决对象组织关系的,并可以根据需要将一些对象进行动态代理。Spring最核心的部分就是它的IoC容器,里面放着各种各样的bean(被Spring容器管理的java对象就叫Spring bean),我们的Java对象的生老病死都交给Spring IoC容器管理了,所以叫做IoC
(Inversion of Control,控制反转了,即对象的创建权限被反转给Spring容器了,而不是我们自己)。在Spring IoC容器创建bean的时候,会根据容器中的信息来按需给bean创建动态代理,创建动态代理的目的是为了增强bean的功能,比如某些bean的方法需要具有事务的功能,那么事务相关的代码就会被放到切面里面,和业务代码不杂糅在一起,这样把非业务需求相关的系统需求织入到bean中的编程方式就是所谓的AOP
(面向切面编程)。
其实,真正完成程序功能的是一个个java对象,你往Spring容器中放入不同的对象,这个容器就具备了不同的能力。比如你放入了KafkaTemplate bean,它就具备了可以发送kafka消息的能力。SpringMVC框架只不过在Spring容器中增加了一些能够处理web请求相关的bean,使得我们能够用SpringMVC来处理web请求。Spring容器只是提供了一个标准化的舞台,你的程序需要哪些功能,就把相应的bean交给Spring容器即可,它会按照你声明的@Autowired
、@PostConstruct
、@Transactional
、@EnableXX
注解等形式将程序有机组合起来,完美交付给你使用。
IoC和AOP常常会被相提并论,其实我想说,它们的地位并不是相等的,AOP只是IoC在创建它的bean的时候用到的一个功能。之所以大家常常会将它们相提并论,是因为AOP确实在Spring框架中被玩出各种花样来,通过AOP,可以将访问数据库的Service方法加入事务的能力,通过AOP,可以给符合某一类条件的方法增加日志,通过AOP,可以统一将应用的RuntimeException进行处理,通过AOP,可以将所有流量入口的方法加上权限校验、入参检验等功能。而AOP就是利用了Spring的BeanPostProcessor
这个扩展点。
好了,下面让我们来通过图片鸟瞰一下Spring框架的工作流程主线:
创建Spring容器(低级容器)
即创建DefaultListableBeanFactory对象,所有的XXApplicationContext内部都有它,不信你就看一下org.springframework.context.support.GenericApplicationContext,它的构造器内就创建了一个DefaultListableBeanFactory,GenericApplicationContext的所有子类的构造器都会调用到GenericApplicationContext的构造器,所以所有的XXApplicationContext内部都会有一个DefaultListableBeanFactory实例
。
做一些准备工作
比如为了让容器具有一些额外特性,对容器进行的一些设置,可以参考org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
方法中做的事情。
装载BeanDefinitons
正如Class是对java类的描述,描述了它有哪些字段,有哪些方法,方法上有哪些注解等等。BeanDefinition就是Spring对它容器中的bean的描述,描述了它的scope(singleton、prototype等),描述了它的beanClass,描述了它的初始化方法,描述了它的依赖的bean名字等等
。有了BeanDefinition,Spring框架就可以用它来创建bean了。那么从哪里获取BeanDefinition呢?可以从xml中获取bean的配置,抽象成BeanDefinition,可以从包中扫描出有@Component、@Service等注解的类,抽象成BeanDefinition,可以从@Configuration类中的@Bean方法抽象成BeanDefinition,甚至你也可以自己创建一个BeanDefinition,将它塞到Spring容器中(通过BeanDefinitionRegistry接口中的方法)。可以看看Spring的org.springframework.context.annotation.AnnotationConfigApplicationContext#register
、org.springframework.context.annotation.AnnotationConfigApplicationContext#scan
、org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions
方法是怎么装载BeanDefinition的。
后置处理一下Spring容器
后置处理,即postProcess,可以给Spring容器增加更多的能力,比如给它添加一些能够注册更多BeanDefinition到Spring容器的BeanFactoryPostProcessor对象(比如ConfigurationClassPostProcessor,它的postProcessBeanDefinitionRegistry方法会从配置类上面解析出来的内容中获取更多的BeanDefinition,典型的注解莫过于MyBatis的@MapperScan注解了,它通常加在配置bean上)。
创建bean
对于前面获得的所有的BeanDefinitions,挨个创建成bean,如果发现某个bean需要依赖另外的bean,就先去创建被依赖的bean,所以当你在IDEA中对org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
方法打断点调试的时候,往往会发现调用栈很深。
创建完bean后还会后置处理它,在初始化方法前可以处理bean(通过各种BeanPostProcessor的postProcessBefore
Initialization方法)。
然后初始化bean,就是调用它的init方法(每个bean创建的时候就会执行它的init方法,而不是等到容器启动完再逐一调用!
)。
执行完初始化方法后,还会后置处理bean(通过各种BeanPostProcessor的postProcessAfter
Initialization方法)。比如找到所有的增强逻辑(增强逻辑在Advisor中,Aspect中的@Around方法和@Pointcut方法会被解析成Advisor),看看它们的pointcut是否match(匹配)当前bean,如果匹配,就为这个bean生成代理对象返回,这样放到容器中的其实是代理对象了(要想获取原来的被代理的对象,也叫目标对象,可以将代理bean安全地强制转换为Advised接口,然后调用getTargetSource().getTarget()方法获取到)。生成代理的方式有JDK动态代理,或者CGLIB的字节码增强。
Spring容器,其实就是Java对象,有两类Spring容器,分别是BeanFactory接口的子类XXBeanFactory,和ApplicationContext接口的子类XXApplicationContext(其实ApplicationContext也继承了BeanFactory接口):
ApplicationContext自己也继承了BeanFactory接口,接口中的方法实现直接委托给XXApplicationContext内部包裹着的DefaultListableBeanFactory
,这样ApplicationContext也可以降级成BeanFactory使用(迪米特法则的应用,也叫最小知道原则,即只暴露它作为BeanFactory的功能出去)。
BeanFactory结尾的容器是低级容器,如果想直接使用它,你需要像AbstractApplicationContext的refresh
方法那样,对它做各种加工,才能让它智能起来。与其让每个人自己去搞这些模版式的代码,不如由Spring自己提供一些高级容器来让使用更方便,所以又有了ApplicationContext结尾的高级容器。高级容器也有好多个,不过不用担心,它们只是在某些地方不一样,从类名上就可以看出来,下面就随便列举几个:
ClassPathXmlApplicationContext
:ClassPathXml前缀表明了它会从类路径的xml中寻找bean。
AnnotationConfigApplicationContext
:AnnotationConfig前缀表明了它的bean都是通过注解定义的,比如@Component、@Bean等,不再从xml中寻找bean。
AnnotationConfigServletWebServerApplicationContext
:ServletWebServer表示它是一个具有Servlet Web功能的容器。
AnnotationConfigReactiveWebServerApplicationContext
:ReactiveWebServer表示它是一个响应式web服务容器(主要用于网关服务)。
Spring框架中很多类的名字很长,但是能让人见名知意,我感觉是一个值得学习的地方。