Java框架篇2-SpringMVC、Spring注解学习笔记

1.SpringMVC执行流程

我把整个流程分成三个阶段

  • 初始化阶段
  • 匹配阶段
  • 执行阶段

1.1SpringMVC-Step1-初始化阶段

请添加图片描述

  1. Web 容器第一次用到 DispatcherServlet 的时候,会创建其对象并执行 init 方法
  2. init 方法内会创建 Spring Web 容器,并调用容器 refresh 方法
  3. refresh 过程中会创建并初始化 SpringMVC 中的重要组件, 例如
    • MultipartResolver(文件上传时,处理multipart格式的表单数据)
    • HandlerMapping(请求映射,浏览器的请求映射到spring中控制器的方法)
    • HandlerAdapter(调用控制器的方法,处理请求)
    • HandlerExceptionResolver(处理调用请求异常)
    • ViewResolver(把字符串解析成视图对象)
  4. 容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet 的成员变量,留待后用

1.2SpringMVC-Step2-匹配阶段

  1. 用户发送的请求统一到达前端控制器 DispatcherServlet

  2. DispatcherServlet 遍历所有 HandlerMapping找到与路径匹配的处理器

    ① HandlerMapping 有多个,每个 HandlerMapping 会返回不同的处理器对象,谁先匹配,返回谁的处理器。其中能识别 @RequestMapping 的优先级最高

    ② 对应 @RequestMapping 的处理器是 HandlerMethod,它包含了控制器对象控制器方法信息

    ③ 其中路径处理器的映射关系在 HandlerMapping 初始化时就会建立好
    请添加图片描述

  3. HandlerMethod 连同匹配到的拦截器生成调用链对象HandlerExecutionChain 返回
    请添加图片描述

  4. 遍历HandlerAdapter 处理器适配器找到能处理 HandlerMethod 的适配器对象,开始调用
    请添加图片描述

1.3SpringMVC-Step3-执行阶段

  1. 执行拦截器 preHandle
    请添加图片描述

  2. HandlerAdapter 调用 HandlerMethod

    ① 调用前处理不同类型的参数

    ② 调用后处理不同类型的返回值

请添加图片描述

  1. 第 2 步没有异常

    ① 返回 ModelAndView

    ② 执行拦截器 postHandle 方法
    请添加图片描述 ③ 解析视图,得到 View 对象,进行视图渲染
    请添加图片描述

  2. 第 2 步有异常,进入 HandlerExceptionResolver 异常处理流程
    请添加图片描述

  3. 最后都会执行拦截器的 afterCompletion 方法

  4. 如果控制器方法标注了 @ResponseBody 注解,则在第 2 步,就会生成 json 结果,并标记 ModelAndView 已处理,这样就不会执行第 3 步的视图渲染

2.Spring+SpringMVC+SpringBoot注解

在这里插入图片描述

  • Spring60个注解
  • web,SpringMVC32个
  • SpringBoot40个

2.1Spring-事务相关注解

  • @EnableTransactionManagement,会额外加载 4 个 bean
    • BeanFactoryTransactionAttributeSourceAdvisor 事务切面类
    • TransactionAttributeSource 用来解析事务属性
    • TransactionInterceptor 事务拦截器
    • TransactionalEventListenerFactory 事务监听器工厂
  • @Transactional
    加载public方法/类上

2.2Spring-核心相关注解

  • @Order :控制bean执行顺序

2.3Spring-切面相关注解

  • @EnableAspectJAutoProxy
    • 会加载 AnnotationAwareAspectJAutoProxyCreator,它是一个 bean 后处理器,用来创建代理
    • 如果没有配置 @EnableAspectJAutoProxy,又需要用到代理(如事务)则会使用 InfrastructureAdvisorAutoProxyCreator 这个 bean 后处理器

2.4Spring-组件扫描与配置类相关注解

在这里插入图片描述


组件扫描

  • @Component

  • @Controller

  • @Service

  • @Repository

  • @ComponentScan


配置类

  • @Conditional

  • @Configuration

    • 配置类其实相当于一个工厂, 标注 @Bean 注解的方法相当于工厂方法
    • @Bean(方法) 不支持方法重载, 如果有多个重载方法, 仅有一个能入选为工厂方法
    • @Configuration 默认会为标注的类生成代理, 其目的是保证 @Bean 方法相互调用时, 仍然能保证其单例特性
    • @Configuration 中如果含有 BeanFactory 后处理器, 则实例工厂方法会导致 MyConfig 提前创建, 造成其依赖注入失败,解决方法是改用静态工厂方法直接为 @Bean 的方法参数依赖注入, 针对 Mapper 扫描可以改用注解方式
  • @Bean

  • @Import

    • 四种用法

      ① 引入单个 bean

      @Configuration
      @Import(Bean1.class) // 1. 引入单个 bean
      
      static class Bean1 {
      
      }
      

      ② 引入一个配置类

      @Import(OtherConfig.class) // 2. 引入一个配置类
      
      @Configuration
      static class OtherConfig {
          @Bean
          public Bean2 bean2() {
              return new Bean2();
          }
      }
      

      ③ 通过 Selector 引入多个类

      @Import(MySelector.class) // 3. 通过 Selector 引入多个类
      
         static class MySelector implements DeferredImportSelector {
            @Override
            public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                return new String[]{Bean3.class.getName(), Bean4.class.getName()};
            }
        }
        static class Bean3 {
      
         }
      
         static class Bean4 {
      
          }
      

      ④ 通过 beanDefinition 注册器

      @Import(MyRegistrar.class) // 4. 通过 beanDefinition 注册器
      
      static class MyRegistrar implements ImportBeanDefinitionRegistrar {
          @Override
          public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
              registry.registerBeanDefinition("bean5", BeanDefinitionBuilder.genericBeanDefinition(Bean5.class).getBeanDefinition());
          }
      }
      static class Bean5 {
      
      	}
      
      • 解析规则

        • 同一配置类中, @Import 先解析 @Bean 后解析

        • 同名定义, 默认后面解析的会覆盖前面解析的

        • 不允许覆盖的情况下, 如何能够让 MyConfig(主配置类) 的配置优先?(虽然覆盖方式能解决)

        • 采用 DeferredImportSelector,因为它最后工作, 可以简单认为先解析 @Bean, 再 Import

          
          public class TestDeferredImport {
          
              public static void main(String[] args) {
                  GenericApplicationContext context = new GenericApplicationContext();
                  DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
                  beanFactory.setAllowBeanDefinitionOverriding(false); // 不允许同名定义覆盖
                  AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
                  context.registerBean(MyConfig.class);
                  context.refresh();
          
                  System.out.println(context.getBean(MyBean.class));
              }
              // 1. 同一配置类中, @Import 先解析  @Bean 后解析
              // 2. 同名定义, 默认后面解析的会覆盖前面解析的
              // 3. 不允许覆盖的情况下, 如何能够让 MyConfig(主配置类) 的配置优先? (虽然覆盖方式能解决)
              // 4. DeferredImportSelector 最后工作, 可以简单认为先解析 @Bean, 再 Import
              @Configuration
              @Import(MySelector.class)
              static class MyConfig { // 主配置 - 程序员编写的
                  @Bean
                  public MyBean myBean() {
                      return new Bean1();
                  }
              }
          
              static class MySelector implements DeferredImportSelector {
          
                  @Override
                  public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                      return new String[]{OtherConfig.class.getName()};
                  }
              }
          
              @Configuration
              static class OtherConfig { // 从属配置 - 自动配置
                  @Bean
                  @ConditionalOnMissingBean
                  public MyBean myBean() {
                      return new Bean2();
                  }
              }
          
              interface MyBean {
          
              }
          
              static class Bean1 implements MyBean {
          
              }
          
              static class Bean2 implements MyBean {
          
              }
          
          }
          
          
  • @Lazy

    • 加在类上,表示此类延迟实例化、初始化
    • 加在方法参数上,此参数会以代理方式注入
  • @PropertySource


2.5Spring-依赖注入

  • @Autowired
  • @Qualifier
  • @Value


2.6SpringMVC-mapping

在这里插入图片描述

  • @RequestMapping,可以派生多个注解如 @GetMapping 等

2.7SpringMVC-rest

在这里插入图片描述

  • @RequestBody
    处理请求体中的json数据,把json数据转换为Java对象
  • @ResponseBody
    把Java对象转换为json数据,写入到响应体
  • @ResponseStatus
  • @RestController :组合了@Controller与@ResponseBody

2.8SpringMVC-统一处理

在这里插入图片描述

  • @ControllerAdvice
  • @ExceptionHandler
    处理异常
  • @RestControllerAdvice:组合了@ResponseBody与@ControllerAdvice

2.9SpringMVC-参数

在这里插入图片描述

  • @PathVariable
    获取请求路径中的参数值

2.10SpringMVC-ajax

  • @CrossOrigin


2.11SpringBoot-auto

在这里插入图片描述

  • @SpringBootApplication
  • @EnableAutoConfiguration
  • @SpringBootConfiguration

2.12SpringBoot-condition

在这里插入图片描述

  • @ConditionalOnClass,classpath 下存在某个 class 时,条件才成立
  • @ConditionalOnMissingBean,beanFactory 内不存在某个 bean 时,条件才成立
  • @ConditionalOnProperty,配置文件中存在某个 property(键、值)时,条件才成立

2.13SpringBoot-boot properties

在这里插入图片描述

  • @ConfigurationProperties,会将当前 bean 的属性与配置文件(.properties)中的键值进行绑定
  • @EnableConfigurationProperties,会添加两个较为重要的 bean
    • ConfigurationPropertiesBindingPostProcessor,bean 后处理器,在 bean 初始化前调用下面的 binder
    • ConfigurationPropertiesBinder,真正执行绑定操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值