1. 定时任务

1.1. 装配流程

  • 打开@EnableScheduling注解
  • @Import(SchedulingConfiguration.class)
  • 注册ScheduledAnnotationBeanPostProcessor的BeanDefinition
    • 这个类实现了ApplicationListener和BeanPostProcessor接口
      • postProcessAfterInitialization()方法
        • 在对类进行初始化的时候会调用这个方法,主要作用是获取bean的所有带有@Scheduled的方法,遍历调用processScheduled()方法,交给线程池执行
      • onApplicationEvent
        • AbstractApplicationContext类的refresh方法,中的finishRefresh调用广播一个ContextRefreshedEvent事件的时候,调用该类的onApplicationEvent()方法
        • 再调用finishRegistration()方法
        • 此方法中会设置taskScheduler,注册的步骤是:
        1. 在容器中查找type=TaskScheduler.class的类
        2. 如果有多个,就根据名字taskScheduler找一次
        3. 如果不存在,就查找type=ScheduledExecutorService.class的类
        4. 如果有多个,就根据名字taskScheduler再找一次
        5. 如果上面执行完,还没找到,那么就执行ScheduledTaskRegistrar.afterPropertiesSet()方法,设置一个单线程的线程池
        • 然后从容器中获取所有SchedulingConfigurer的实现类,执行对应的configureTasks()方法,将任务加入到ScheduledTaskRegistrar的各类task列表中
  • 其他

    • 在springboot2.1版本之后提供了一个TaskSchedulingAutoConfiguration类,在springboot启动时会自动装配,此时会初始化一个TaskScheduler,类型是ThreadPoolTaskScheduler,线程池的线程只有一个,产生的线程名字的前缀是scheduling-,方便在配置文件中直接修改对应的默认设置

      2. 异步任务

      2.1. 装配流程

  • 打开@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注解指定的线程池,如果没有指定就是用默认的,也就是上面的默认线程池来执行任务
  • 其他

    • 在springboot2.1版本之后从spring.factories文件中初始化TaskExecutionAutoConfiguration类,会提供一个核心线程数为8,最大线程数Integer.MAX_VALUE,任务队列大小为Integer.MAX_VALUE的线程池用来作为异步任务的默认线程池

      3. Bean的生命周期

  • 通过*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方法,那么调用对应的方法
  • 此时初始化完成之后,放入二级和一级缓存
  • 如果实现了DisposableBean接口,放入对应的map中
  • 如果Bean是一个FactoryBean,那么执行对应的getObject方法,得到实例对象
  • 容器关闭的时候,执行对应的销毁方法
    • 如果有@PreDestroy注解的方法,调用这个方法
    • 如果实现了DisposableBean接口,调用destroy方法
    • 如果配置了destroy-method,执行配置的这个方法

      3. Tomcat处理流程

  1. 用户浏览器发送请求
  2. 请求会发送到对应的Connector监听的Socket端口
  3. Connector从Socket流中获取数据,然后根据Http协议将其解析为Request和Reponse对象
  4. 找到Request对象对应的Host,Context,Wrapper,通过一系列处理,执行过滤器,然后交给DispatcherServlet的doService方法处理
  5. DispatcherServlet收到请求调用处理器映射器HandlerMapping。
  6. 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
  7. DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
  8. 执行处理器Handler(Controller,也叫页面控制器)。
  9. Handler执行完成返回ModelAndView
  10. HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
  11. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  12. ViewReslover解析后返回具体View
  13. DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)
  14. DispatcherServlet响应用户

image.png

4. 自动装配部分

  1. 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整合部分

  1. 依赖于上述的自动装配<br /> @MapperScan @Import(MapperScannerRegistrar.class)<br /> MapperScannerRegistrar 实现了 ImportBeanDefinitionRegistrar<br /> registerBeanDefinitions registerBeanDefinitions 注册了MapperScannerConfigurer这个BeanDefinition<br /> MapperScannerConfigurer 实现了 BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware<br /> 实现了 BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry方法,将扫描指定路径下的所有接口并注册为一个个的beanclass=MapperFactoryBeanBeanDefinition<br /> spring.factories MybatisAutoConfiguration <br /> 初始化一些需要注入mapperbean的时候,接着实例化mapper,也就是MapperFactoryBean时,因为父类SqlSessionDaoSupport有一个set注入的SqlSessionTemplateSqlSessionTemplate有一个set方法,然后根据PropertyDescriptor这个部分,需要初始化SqlSessionFactoryBean,然后会调用MybatisAutoConfiguration中提供的@Bean注解的SqlsessionFactory方法进行初始化SqlsessionFactory,这里会处理配置文件中mybatis开头的的配置项信息,然后调用SqlSessionFactoryBeangetObject方法,最后会调用到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的成员变量MapperRegistryknownMappers中,同时会对对应的接口用MapperAnnotationBuilder进行mybatis@Select这类注解的解析,并没有在mapper文件中的SQL操作将之封装为一个个MappedStatement放入Configuration中。<br /> <br /> 如果mapperLocations不包括某个mapper接口的话,因为它是一个个MapperFactoryBean,最终继承了DaoSupport,这个类实现了InitializingBean接口,在初始化阶段调用invokeInitMethods的时候会执行这个类的afterProperties方法,会调用到MapperFactoryBeancheckDaoConfig方法,最终会对这个mapper接口进行扫描处理,将之封装为MapperProxyFactory放入Configuration的成员变量MapperRegistryknownMappers中,他的方法封装为MappedStatement放入到Configuration中。然后再调用对应的getObject方法获取真正的代理生成的Mapper对象,从MapperRegistryknownMappers中获取到对应的MapperProxyFactory,然后调用newInstance方法(这里的InvacationHandlerMapperProxy,后续真正调用mapper的方法的时候是调用这里的invoke回调方法进行处理),进行代理对象的生成,并注入到需要的地方,至此mapper的初始化和注入完成。<br /> 在调用的时候,会直接调用对应MapperProxyinvoke方法,会判断方法有没有缓存,没有缓存的话,会实例化PlainMethodInvoker,在实例化这个类的时候需要传入一个MapperMethod对象,这里会将对应的接口、方法、Configuration信息封装为一个MapperMethod对象,用来实例化PlainMethodInvoker。然后调用PlainMethodInvokerinvoke方法,最终会调用ampperMethodexecute方法,参数是sqlsession实际最后是交给SqlSessionTemplate去执行对应的crud操作,然后会调用SqlSessionTemplate方法的sessionFactory.openSession获取连接,在获取连接的时候创建一个Executor,默认是SimpleExecutor,如果设置了cacheEnabled=true的话,那么会包装成一个CachingExecutor,如果有插件的话,在这里会对这个Executor进行层层代理。<br /> 然后会将ConfigurationExecutor封装为一个DefaultSqlSession返回,然后调用这个类的curd方法,最终的所有方法都是由它的Executor执行的。<br /> 如果开启二级缓存也就是mapper中有了<cache/>标签或者使用了<cache-ref>的配置,用的是CachingExecutor执行crud操作,二级缓存有,就从二级缓存取,如果二级缓存没有,<br /> 就从一级缓存取,如果一级缓存没有就查询数据库,然后放入一级再放入二级,如果配置项local-cache-scope=statement那么会清理掉一级缓存<br /> 执行上面的后半部分<br />