1. 定时任务
1.1. 装配流程
- 打开@EnableScheduling注解
- @Import(SchedulingConfiguration.class)
- 注册ScheduledAnnotationBeanPostProcessor的BeanDefinition
- 这个类实现了ApplicationListener和BeanPostProcessor接口
- postProcessAfterInitialization()方法
- 在对类进行初始化的时候会调用这个方法,主要作用是获取bean的所有带有@Scheduled的方法,遍历调用processScheduled()方法,交给线程池执行
- onApplicationEvent
- AbstractApplicationContext类的refresh方法,中的finishRefresh调用广播一个ContextRefreshedEvent事件的时候,调用该类的onApplicationEvent()方法
- 再调用finishRegistration()方法
- 此方法中会设置taskScheduler,注册的步骤是:
- 在容器中查找type=TaskScheduler.class的类
- 如果有多个,就根据名字taskScheduler找一次
- 如果不存在,就查找type=ScheduledExecutorService.class的类
- 如果有多个,就根据名字taskScheduler再找一次
- 如果上面执行完,还没找到,那么就执行ScheduledTaskRegistrar.afterPropertiesSet()方法,设置一个单线程的线程池
- 然后从容器中获取所有SchedulingConfigurer的实现类,执行对应的configureTasks()方法,将任务加入到ScheduledTaskRegistrar的各类task列表中
- postProcessAfterInitialization()方法
- 这个类实现了ApplicationListener和BeanPostProcessor接口
其他
打开@EnableAsync注解
- @Import(AsyncConfigurationSelector.class)
- 在AbstractApplicationContext的refresh方法中,调用invokeBeanFactoryPostProcessors()方法
- ConfigurationClassParser类的processImports方法,会调用AsyncConfigurationSelector的selectImports方法,最终通过ConfigurationClassPostProcessor的loadBeanDefinitions方法将AsyncAnnotationBeanPostProcessor的BeanDefinition注册到容器中,等待后续的初始化
- 同时也会这里会注入一个beanName=applicationTaskExecutor的ThreadPoolTaskExecutor的bean定义信息到容器中,等到后续的初始化。这个是TaskExecutionAutoConfiguration提供的
- 在AsyncAnnotationBeanPostProcessor的setBeanFactory方法中,然后会new AysncAnnotaionAdvisor(),在构造方法中会对所有@Async标注的方法生成切面和切点,进行AOP相关的织入操作,同时会设置默认的defaultExecutor,如果没有设置beanName=”taskExecutor”的bean或者类型是TaskExecutor的类,那么会使用默认的,也就是一个任务就new一个线程的异步线程池。(2.1.0版本之后提供了一个默认的线程池,见下文)
- 每次通过代理调用@Async注解标注的方法时,会调用AsyncExecutionAspectSupport的determineAsyncExecutor()方法用来获取@Async注解指定的线程池,如果没有指定就是用默认的,也就是上面的默认线程池来执行任务
其他
通过*BeanDefinitionReader读取XML、注解、Properties中的Bean定义信息读取为一个个的BeanDefinition,并交给BeanDefinitionRegistry管理
- 在refresh的时候会执行invokeBeanFactoryPostProcessor方法去调用BeanDefinitionRegistryPostProcessor的相关方法,去注册额外的bean定义信息
- 然后开始初始化Bean
- 先从singletonObjects中查找
- 如果不存在,然后再从earlySingletonObjects获取bean
- 如果还不存在,判断是否有父容器,如果存在就从父容器中获取,否则就自行执行初始化操作
- 先将beanName放入DefaultSingletonBeanRegistry的singletonsCurrentlyInCreation中,表示当前bean正在创建
- 通过反射调用构造方法实例化对象,如果此处是通过构造方法注入,需要在此时处理依赖注入
- 实例化完成,然后会放入三级缓存,用于解决循环依赖
- 实例化完成之后,开始执行初始化操作
- populateBean方法
- 字段注入在这里处理。调用的是AutowiredAnnotationBeanPostProcessor的postProcessProperties方法
- initializeBeanalize方法
- 如果实现了*Aware接口,那么调用对应的方法
- 调用BeanPostProcessor的postProcessBeforeInitialization方法,这里会处理@PostConstructor注解的方法。
- AOP在这里处理,在调用BeanPostProcessor的后处理applyBeanPostProcessorsAfterInitialization方法, 最终调用AbstractAutoProxyCreator类的postProcessAfterInitialization方法
- 调用Init-Method
- 如果实现了InitializingBean接口,调用afterPropertiesSet方法
- 如果配置了init-method方法,那么调用对应的方法
- populateBean方法
- 此时初始化完成之后,放入二级和一级缓存
- 如果实现了DisposableBean接口,放入对应的map中
- 如果Bean是一个FactoryBean,那么执行对应的getObject方法,得到实例对象
- 容器关闭的时候,执行对应的销毁方法
- 用户浏览器发送请求
- 请求会发送到对应的Connector监听的Socket端口
- Connector从Socket流中获取数据,然后根据Http协议将其解析为Request和Reponse对象
- 找到Request对象对应的Host,Context,Wrapper,通过一系列处理,执行过滤器,然后交给DispatcherServlet的doService方法处理
- DispatcherServlet收到请求调用处理器映射器HandlerMapping。
- 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
- DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
- 执行处理器Handler(Controller,也叫页面控制器)。
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)
- DispatcherServlet响应用户
4. 自动装配部分
AnnotationConfigServletWebServerApplicationContext <br /> 无参构造方法 AnnotatedBeanDefinitionReader <br /> AnnotationConfigUtils.registerAnnotationConfigProcessors <br /> ConfigurationClassPostProcessor AutowiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor<br /> refresh<br /> invokeBeanFactoryPostProcessors<br /> invokeBeanDefinitionRegistryPostProcessors <br /> ConfigurationClassPostProcessor-postProcessBeanDefinitionRegistry <br /> ConfigurationClassParser.parse doProcessConfigurationClass processImports deferredImportSelectorHandler.process<br /> @EnableAutoConfiguration <br /> @Import(AutoConfigurationImportSelector) <br /> process getAutoConfigurationEntry <br /> getCandidateConfigurations <br /> SpringFactoriesLoader.loadFactoryNames<br /> getSpringFactoriesLoaderFactoryClass<br /> ConfigurationClassBeanDefinitionReader.loadBeanDefinitions
5. Mybatis整合部分
依赖于上述的自动装配<br /> @MapperScan @Import(MapperScannerRegistrar.class)<br /> MapperScannerRegistrar 实现了 ImportBeanDefinitionRegistrar<br /> registerBeanDefinitions registerBeanDefinitions 注册了MapperScannerConfigurer这个BeanDefinition<br /> MapperScannerConfigurer 实现了 BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware<br /> 实现了 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry方法,将扫描指定路径下的所有接口并注册为一个个的beanclass=MapperFactoryBean的BeanDefinition<br /> spring.factories MybatisAutoConfiguration <br /> 初始化一些需要注入mapper的bean的时候,接着实例化mapper,也就是MapperFactoryBean时,因为父类SqlSessionDaoSupport有一个set注入的SqlSessionTemplate,SqlSessionTemplate有一个set方法,然后根据PropertyDescriptor这个部分,需要初始化SqlSessionFactoryBean,然后会调用MybatisAutoConfiguration中提供的@Bean注解的SqlsessionFactory方法进行初始化SqlsessionFactory,这里会处理配置文件中mybatis开头的的配置项信息,然后调用SqlSessionFactoryBean的getObject方法,最后会调用到buildSqlSessionFactory方法,这里会处理所有的myabtis-config相关的东西。<br /> 如果此处有设置mapperLocations配置项,那么通过MapperBuilderAssistant去解析对应路径下的mapper文件,这个类有一个成员变量MapperBuilderAssistant(这个类是用来管理namespace与二级缓存Cache的对应关系的,每个MappedStatement有一个Cache,这个Cache就是MapperBuilderAssistant的成员变量Cache,这样保证一个namespace下的所有statement共享同一个cache,用标签<cache/>打开。当然可以通过<br /> <cache-ref namespace="">来使得当前的namespace与指定的namespace共用同一个cache。每个Cache有一个cacheId用来唯一标识这个cache,这个id就是namespace)。并将所有的SQL(DML\DQL)操作封装为一个个MappedStatement放入到Configuration中,同时也会将mapper文件中namespace指定的接口最终包装为一个个MapperProxyFactory放入Configuration的成员变量MapperRegistry的knownMappers中,同时会对对应的接口用MapperAnnotationBuilder进行mybatis的@Select这类注解的解析,并没有在mapper文件中的SQL操作将之封装为一个个MappedStatement放入Configuration中。<br /> <br /> 如果mapperLocations不包括某个mapper接口的话,因为它是一个个MapperFactoryBean,最终继承了DaoSupport,这个类实现了InitializingBean接口,在初始化阶段调用invokeInitMethods的时候会执行这个类的afterProperties方法,会调用到MapperFactoryBean的checkDaoConfig方法,最终会对这个mapper接口进行扫描处理,将之封装为MapperProxyFactory放入Configuration的成员变量MapperRegistry的knownMappers中,他的方法封装为MappedStatement放入到Configuration中。然后再调用对应的getObject方法获取真正的代理生成的Mapper对象,从MapperRegistry的knownMappers中获取到对应的MapperProxyFactory,然后调用newInstance方法(这里的InvacationHandler是MapperProxy,后续真正调用mapper的方法的时候是调用这里的invoke回调方法进行处理),进行代理对象的生成,并注入到需要的地方,至此mapper的初始化和注入完成。<br /> 在调用的时候,会直接调用对应MapperProxy的invoke方法,会判断方法有没有缓存,没有缓存的话,会实例化PlainMethodInvoker,在实例化这个类的时候需要传入一个MapperMethod对象,这里会将对应的接口、方法、Configuration信息封装为一个MapperMethod对象,用来实例化PlainMethodInvoker。然后调用PlainMethodInvoker的invoke方法,最终会调用ampperMethod的execute方法,参数是sqlsession实际最后是交给SqlSessionTemplate去执行对应的crud操作,然后会调用SqlSessionTemplate方法的sessionFactory.openSession获取连接,在获取连接的时候创建一个Executor,默认是SimpleExecutor,如果设置了cacheEnabled=true的话,那么会包装成一个CachingExecutor,如果有插件的话,在这里会对这个Executor进行层层代理。<br /> 然后会将Configuration、Executor封装为一个DefaultSqlSession返回,然后调用这个类的curd方法,最终的所有方法都是由它的Executor执行的。<br /> 如果开启二级缓存也就是mapper中有了<cache/>标签或者使用了<cache-ref>的配置,用的是CachingExecutor执行crud操作,二级缓存有,就从二级缓存取,如果二级缓存没有,<br /> 就从一级缓存取,如果一级缓存没有就查询数据库,然后放入一级再放入二级,如果配置项local-cache-scope=statement那么会清理掉一级缓存<br /> 执行上面的后半部分<br />