spring-context模块笔记,该模块是Spring容器的核心部分,继承关系和结构也很复杂,值得细细看
核心接口和类
ApplicationContext:核心接口定义.继承了环境信息,工厂信息,事件发布,资源加载接口
AbstractApplicationContext:提供ApplicationContext的基本实现,最主要定义了refresh方法,也就是刷新流程定义,让子类重写钩子即可完成拓展,非常的灵活
AbstractRefreshableApplicationContext:提供了refreshBeanFactory()抽象方法的实现,使用DefaultListableBeanFactory为默认的BeanFactory,提供
loadBeanDefinitions抽象方法,让子类专注于通过各种方式加载BeanDefinition
AbstractXmlApplicationContext和ClassPathXmlApplicationContext:loadBeanDefinitions实现从classpath路径下载入xml解析BeanDefinition方式
AnnotationConfigWebApplicationContext:目前使用较多的容器对象,loadBeanDefinitions实现为扫描注解加载BeanDefinition
上面列出的接口和类都是容器中极其核心的部分
整体概览
Context可以理解为对BeanFactory的封装.包含BeanFactory选择/配置/Bean来源加载/定义容器启动流程,为其提供上下文以及丰富的拓展,这是直面使用者的接口.
主要的refresh方法在AbstractApplicationContext中实现,它定义了核心流程,包括初始化BeanFactory,加载BeanDefinition,触发BeanDefinitionRegistry以及BeanFactory的PostProcessor后置方法,支持重复刷新以及Context继承关系,发布容器刷新成功消息等,细节非常多.
子类的核心实现就是实现loadBeanDefinitions抽象方法,提供不同渠道加载BeanDefinition能力就是子类最大的不同,整体流程上是完全一样的.
功能流程接口与组件说明
ConfigurationClassPostProcessor:通过BeanFactoryPostProcessor引入了注解部分的实现流程
ConfigurationClassParser:配置注解@Configuration类的核心实现.以及自定义注解的流程处理 内部较复杂,大量嵌套,循环,跨方法递归.
AnnotationBeanNameGenerator:注解类的命名规则实现.如果使用注解指定名字则选取(如:@Component@ManagedBean@Named),否则回退到使用短名称类名
ApplicationContextInitializer:在refresh()前的回调方法,用于调整BeanFactory以及自定义配置
BeanDefinition解析相关
XML方式
BeanDefinitionDocumentReader:将xml定义的整个文档对象Document进行注册,这是外部接入的顶层接口,默认DefaultBeanDefinitionDocumentReader类实现.主要方法是parseBeanDefinitions,他会遍历所有子节点,如果有beans元素则进行初始递归
BeanDefinitionParserDelegate:核心解析类.包含所有的默认节点解析,以及自定义节点的空间映射委托处理
NamespaceHandler:自定义命名空间处理器.相当于一个空间的处理者.主要实现是NamespaceHandlerSupport.将BeanDefinitionParser进行管理.比如典型AopNamespaceHandler,MvcNamespaceHandler等都会将自己定义的节点管理起来,很多标签名都很眼熟
BeanDefinitionParser:自定义标签解析成BeanDefinition的实现.这个就太多了,主要是将节点信息转换成实际的BeanDefinition供后续加载
注解方式
ConfigurationClassParser:注解配置和核心启动类,负责定义完整注解配置解析流程
AnnotatedBeanDefinitionReader:注解bean的BeanDefinition解析接入层
ScannedGenericBeanDefinition:使用扫描class文件产生的BeanDefinition信息,它是通过访问者模式将BeanDefinition信息填充完整,可以不加载Class对象
AnnotatedGenericBeanDefinition:直接使用Class对象将BeanDefinition信息填充完成
Context中的Event事件管理
ApplicationEventMulticaster:事件分发器.主要是管理事件监听器的,对应就是被监听者
ApplicationEvent:事件.比如应用创建完成之后会推送借助事件分发器推送应用创建事件ContextStartedEvent
ApplicationListener:事件监听器.一般来说用的比较多的都是自己实现接口,然后监听想要处理的事件.
EventListenerMethodProcessor:将EventListener注解的方法转为ApplicationListenerMethodAdapter进而注册事件监听器
EventListenerFactory:事件监听工厂-对@EventListener注解返回ApplicationListenerMethodAdapter对象进行监听适配
ApplicationListenerDetector:将容器中实现了ApplicationListener的监听器注册到Context中以支持Context进行发布事件
Spring的事件管理还是挺好的,不过仅限在单应用中,如果希望跨应用传播事件,可以参考Spring Cloud Bus的思路,通过mq传播到整个服务中
按照包功能依次展开
Expression
StandardBeanExpressionResolver:提供SPEL部分的引入支持
主要配置了PropertyAccessor,如BeanExpressionContextAccessor,EnvironmentAccessor等
引入BeanFactoryResolver对beanName获取bean的支持,引入ConversionService支持
Support
里面有多种ApplicationContext的实现类.这些实现类一部分是因加载配置的方式不同而略有区别,比如说在classpath目录/自定义文件路径.另一部分是为了提供不同的方式载入配置,比如说xml/注解的形式开启.他们主要是重写了loadBeanDefinitions这个方法,然后以不同的方式载入BeanDefinition.
类层级以及主要实现类
AbstractApplicationContext-定义了整个刷新流程
--AbstractRefreshableApplicationContext-支持刷新,主要是刷新时清理已经创建的bean,绝大多数的Context的基类
----AbstractXmlApplicationContext-xml配置启动容器基类
------ClassPathXmlApplicationContext-在classpath目录下加载xml配置启动容器
------FileSystemXmlApplicationContext-以资源的形式独立加载xml配置启动容器
--GenericApplicationContext-不支持刷新的通用的上下文,所有的配置需要手工处理
----AnnotationConfigApplicationContext-支持注册带注解的配置类注册,目前使用非常多
----GenericXmlApplicationContext-支持xml路径参数解析配置类注册
----StaticApplicationContext-不支持外部配置注册,必须手工注册,一般测试用这个,这个是比较干净的容器,跑起来快
--AbstractRefreshableWebApplicationContext-web模块context的基类
----AnnotationConfigWebApplicationContext-以注解的形式开启web容器,目前使用非常多
----XmlWebApplicationContext-以xml配置的形式启动容器
主要的容器类就这些,使用比较多的都加黑了,由于现在的主流开发方式都是注解开发,因此注解启动容器上下文使用较多.
MessageSource
国际化支持提供了一些加载方式和存储特征
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
StaticMessageSource
Schedule
@EnableScheduling开启调度任务.引入SchedulingConfiguration配置,进而加载ScheduledAnnotationBeanPostProcessor将注解@Scheduled进行解析
@EnableAsync开启异步执行任务.引入AsyncConfigurationSelector配置,选择加载ProxyAsyncConfiguration或AspectJAsyncConfiguration配置类,进一步加载AsyncAnnotationBeanPostProcessor,这个AsyncAnnotationBeanPostProcessor实际上会对标有@Async的类和方法进行过滤(AsyncAnnotationAdvisor类实现),匹配到的方法就会产生AOP代理,进而异步执行(实际方法拦截器为AnnotationAsyncExecutionInterceptor)
ReschedulingRunnable-通过Trigger获取下个执行时间点,不断的触发task执行.这样Trigger就可以专注于获取下次执行时间,如CronTrigger可以专注表达式
TaskScheduler-任务管理器接口,主要实现有ConcurrentTaskScheduler并发任务管理器,其主要依赖ScheduledExecutorService线程池
ScheduledTaskRegistrar-主要便于管理各种Task,最终还是执行TaskScheduler调度方法.
Validation
@Validated:验证注解,放在类,方法,参数级别均可生效,等效于@Valid
MethodValidationPostProcessor:类级别的@Validated注解AOP生成,这里的AOP生成还是很通用的,如果需要自己写切面的话,可以学习下,值得借鉴
DataBinder:绑定器.允许对目标对象的属性设值,类型转换,验证,返回错误信息等操作.http请求的参数很多都是依托于DataBinder进行数据绑定和验证处理
常用注解说明
@Configuration:配置类声明,
@Bean:标注方法声明一个Bean.需要在@Configuration声明的类中使用
@ComponentScan和@ComponentScans:包路径扫描加载Bean声明.需要在@Configuration声明的类中使用
@Conditional:加载Bean的条件限制.
@DependsOn:指出依赖关系,让容器让制先加载依赖的bean.一般情况下非显示的引用依赖但是又依赖别的Bean初始化信息会选择这个注解
@Import:加载指定的配置类Class对象到容器中.其中Class类如果是ImportSelector和ImportBeanDefinitionRegistrar接口的实现类则会让使用者自定义,动态的依据参数选择导入配置类
@ImportResource:指加载xml的配置
@Lazy:将容器初始化时加载延迟到使用时加载
@Primary:指多个Bean同类型引用时按照类型注入选择一个标注此注解的Bean进行注入
@Profile:对@Conditional的一个实际运用.抽象出配置文件的概念
@PropertySource和@PropertySources:指加载指定的配置文件到环境中便于直接使用
@Role:定义Bean的角色,有些类加载限制为"基础设施"配置,这是框架内部分辨.它的默认值是BeanDefinition#ROLE_APPLICATION
@Scope:作用域.比如单例ConfigurableBeanFactory#SCOPE_SINGLETON
@EventListener:事件监听器方法注解.方便的处理监听方法,支持SPEL表达式条件处理监听方法
@EnableScheduling开启调度任务.配合@Scheduled注解标注调度任务方法
@EnableAsync开启异步执行.配合@Async注解标注异步对应的类和方法
@Validated验证注解,放在类,方法,参数级别均可生效
@EnableAspectJAutoProxy:引入AspectJAutoProxyRegistrar进而将类AnnotationAwareAspectJAutoProxyCreator注册,它会解析@Aspect注解
@Configuration类的核心实现流程
实现类为ConfigurationClassParser
1判断是否含有@Conditional注解,需满足条件注解方可加载
2对配置类进行向父类循环解析配置
3解析配置流程
3.1处理嵌套的内部@Configuration注解配置类.递归到步骤1进行处理
3.2处理@PropertySource和@PropertySources注解.向环境中添加对应的配置信息
3.3处理@ComponentScan和@ComponentScans注解.如果扫到到的配置中含有@Configuration注解,递归到1进行处理.实现通过ClassPathBeanDefinitionScanner类,这里大部分方法都是core包和beans包提供的对象.
3.4处理@Import注解
3.4.1如果导入类为ImportSelector实现类.取出导入类,递归自己
3.4.2如果导入类为ImportBeanDefinitionRegistrar实现类.先放起来,后面处理
3.4.3其他情况递归到步骤1处理
3.5处理@ImportResource注解
3.6处理@Bean注解对应的方法
3.7处理接口上的@Bean注解对应的方法
3.8返回父类供步骤2判断是否到Object对象
从@Configuration的解析过程可以看出通过注解的方式将对象加入到容器中的所有方式有以下几种
1@Import配置类(ImportSelector选择性导入,ImportBeanDefinitionRegistrar自定义导入(一般会进行自定义扫描))自定义加载Bean
2@Bean注解直接声明Bean
3@ComponentScan扫描注解载入Bean
4@ImportResource加载xml解析载入Bean
5@Configuration解析上述所有规则
所有的注解载入流程都是这套,无出其右(上述加载Bean都是指加载BeanDefinition,因为还没到初始化Bean的时刻)
附:refresh方法的主要流程,看注释说明
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备上下文环境
prepareRefresh();
// 让子类创建beanFactory,以及让子类添加一些自定义的BeanDefinition.这里对于框架来说进行了大量的拓展
// 在刷新的初始阶段就要子类将BeanDefinition加载进来,子类一般继承AbstractRefreshableApplicationContext类,实现抽象方法loadBeanDefinitions进行加载BeanDefinition,常用的子类实现有ClassPathXmlApplicationContext(XML加载)和AnnotationConfigWebApplicationContext(注解加载)两种
// 这里还需要加载一些自定义的类以及注册核心功能的BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor用来实现框架基础
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 自己调整beanFactory的一些配置,比如忽略接口,添加Classloader,添加一些默认的BeanPostProcessor,再注册一些默认提供的BeanDefinition对象,如Environment,SystemProperties
prepareBeanFactory(beanFactory);
try {
// 让子类调整beanFactory
postProcessBeanFactory(beanFactory);
// 触发BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的beanFactory后置方法
invokeBeanFactoryPostProcessors(beanFactory);
// 将注册的BeanPostProcessor都取出来放到容器中,供BeanFactory在后续bean初始化前后回调
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 让子类加载自定义的一些特殊bean,比如web容器相关的
onRefresh();
// 从容器中取出来ApplicationListener监听器供后续使用
registerListeners();
// 可以开始实例化非延迟的bean了
finishBeanFactoryInitialization(beanFactory);
// 发布完成刷新事件以及清理部分缓存等
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 将已创建的Bean都销毁掉
destroyBeans();
// 设置false标志
cancelRefresh(ex);
// 继续传播异常
throw ex;
}
finally {
// 清理缓存
resetCommonCaches();
}
}
}