栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot底层原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot底层原理

SpringBoot 一、基本注解 1、@configration详解
---------------------------------------------------------------------
@Configuration(proxyBeanMethods = true) //被该注解声明的类为配置类 == 配置文件(beans.xml)
@Import({user.class, DBHelper.class})
public class MyConfig {
    @Bean //给容器中添加组件,以方法名作为组件ID,返回类型为组件类型,返回值就是容器中的对象(实例)
    public user user01(){
        user us = new user("小蔡", 20);
        us.setPet(userPet());
//        System.out.println("宠物是==>"+userPet());

        return us;
    }
   @Bean("My")
    public Pet userPet(){
        return new Pet("哈士奇","宠物狗");
    }
}
-------------------main--结果为第一张运行图----------------------
      user user01 = run.getBean("user01", user.class);
      Pet bean = run.getBean("My", Pet.class);
      System.out.println("用户的宠物:"+(user01.getPet() == bean));
-------------------main--结果为第二张运行图----------------------
	 //通过import组件导入的俩个组件进行获取组件
        String[] beanNamesForType = 				          run.getBeanNamesForType(user.class);
        for (String beng : beanNamesForType) {
            System.out.println("实体类的组件名称:"+beng);
        }
        DBHelper helper = run.getBean(DBHelper.class);
        System.out.println("组件名称:"+helper);
----------------------------------------------------------------

2、@Conditional详解
@ConditionalOnBean(name = "My") //该注解加载到类上,表明下列组件中没有“My”组件,则所有组件都不生效
 @Configuration(proxyBeanMethods = true) //被该注解声明的类为配置类 == 配置文件(beans.xml)
public class MyConfig { 
    // 加载到某一个具体的方法上时,表名如果没有该组件,则该方法不被加载
       @ConditionalOnBean(name = "My") 
//给容器中添加组件,以方法名作为组件ID,返回类型为组件类型,返回值就是容器中的对象(实例)
    @Bean 
    public user user01(){
        user us = new user("小蔡", 20);
        us.setPet(userPet());
//        System.out.println("宠物是==>"+userPet());

        return us;
    }
//   @Bean("My")
    public Pet userPet(){
        return new Pet("哈士奇","宠物狗");
    }
}
-------------------main--结果为第一张运行图----------------------
    boolean my = run.containsBean("My");
        System.out.println("容器中是否存在该组件:"+my);

        boolean containsBean = run.containsBean("user01");
        System.out.println("容器中是否存在该组件:"+containsBean);     

3、@ImportResource详解

使用场景:在配置文件中导入过多的组件,想迁移成注解的方式。就可以用该注解,重新解析

-------------------xml文件中配置属性值---------------------------

        
        

-------------通过@ImportResource注解注入到容器中-----------------
 @ImportResource("classpath:bean.xml")
-------------------main--结果为第一张运行图----------------------
		boolean pet = run.containsBean("pet");
        System.out.println("容器中是否有该组件:"+pet);

4、配置绑定

使用场景:将实体类中的属性值通过配置文件(.properties/.yaml)进行赋值,通过@ConfigurationProperties(prefix = “mypet”)绑定前缀,并且通过添加组件的注解,把其加载到容器中去

方式一:@Component+@ConfigurationProperties(prefix = "mypet")
@Component
@ConfigurationProperties(prefix = "mypet")//绑定配置文件中的属性值
@Data
public class Pet {
    private String name;
    private String PetType;
}
--------------(.properties/.yaml)配置文件----------------------
mypet.name=ynu
mypet.PetType=mi
-------------------main-----------------------------------------
@RestController
public class FirstController {
    @Autowired
    Pet pet;
        @RequestMapping("/go")
    public Pet pet(){
        return pet;
    }
}
----------------------------方式二-------------------------------
在配置类(Config)中开启自动绑定,使用该注解就无须在实体类上添加注明添加组件的注解。
    主要用到:实体类可能是第三方包,并没有在类上添加组件的注解
@EnableConfigurationProperties(Pet.class)
    //1、开启Pet配置绑定功能
    //2、把Pet组件自动注入到容器中去
//同时需要关联实体类中的属性
@ConfigurationProperties(prefix = "mypet")

二、自动配置原理 1、引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
  1. @SpringBootConfiguration

    • @Configuration:代表当前是一个配置类

    • @ComponentScan:指定扫描包

    • @EnableAutoConfiguration —>这三个注解就相当于**@SpringBootConfiguration** 一个注解

      • @AutoConfigurationPackage
        @Import({AutoConfigurationImportSelector.class})
        public @interface EnableAutoConfiguration {}
        
      • @AutoConfigurationPackage:自动配置包

      • @Import({Registrar.class}) //给容器中导入组件
        public @interface AutoConfigurationPackage {}
        //利用Registrar给容器中导入一系列组件
        //将指定包下的所有的组件导入容器中。这就解释了为什么默认的包路径是Main程序所在的包
        

        @Import({AutoConfigurationImportSelector.class})(核心)

        1. 该方法给容器中导入批量的组件

           AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
          
        2. 调用该方法获取到所有需要导入到容器中的组件(134个)

          List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
          

        1. 利用加载工厂得到所有的组件
        Map> loadSpringFactories(ClassLoader classLoader)
        
        1. 从META-INF/spring.factories位置来加载文件
                      Enumeration urls = classLoader.getResources("META-INF/spring.factories");
        

        默认扫描我们当前系统中所有META-INF/spring.factories位置的文件,其核心文件就是spring-boot-autoconfigure中的spring.factories

        1. 按需开启自动配置项
        • 134个场景的自动配置组件,在启动的时候默认全部加载
        • 但最终按照条件装配注解,@ConditionalOnClass该注解就是来确定包下是否有某一个需要加载的类,@ConditionalOnBean确定组件
        1. 修改默认配置
        @Bean
        //容器中有这个类型的组件
        @ConditionalOnBean({MultipartResolver.class})
        @ConditionalOnMissingBean(
        //容器中没有这个名字multipartResolver的组件时
        name = {"multipartResolver"})
        //调用multipartResolver方法,传入参数,并且将参数返回出去,并且将返回值放在容器中
              public MultipartResolver multipartResolver(MultipartResolver resolver) {
        //如果@Bean注解下的方法中有对象参数,这个参数值名称就会从容器中去找,即使用户配置的文件上传解析器名称不是multipartResolver,也会从容器中去找,然后返回出去
                  return resolver;
              }
        
    2、自动配置流程总结
    1. SpringBoot会通过@SpringBootApplication注解下的@EnableAutoConfiguration中的@Import({AutoConfigurationImportSelector.class})加载所有的自动配置类
    2. 每个自动配置类按照条件注解@ConditionalOnClass或者@ConditionalOnMissingClass来决定是否生效,并且默认绑定xxxProperties.class类中指定的值和配置文件(springboot工程下的application.properties)进行绑定
    3. 生效的配置类就会默认给容器中装配组件:比如导入springmvc依赖就会有DispathcherServlet的配置类
    4. 定制化配置
      1. 用户通过在自定义的@Configuration类中,通过@Bean注解添加相应的组件,就会代替底层自动装配的组件
      2. 用户通过获取该配置文件的配置前缀,去修改对应的配置,比如修改缓存:prefix = “spring.cache”—>拿到前缀即可修改
    5. 查看自动配置装配了哪些
      1. 可以在配置文件中配置debug=true,开启自动配置报告。Negative matches(表示没生效的自动配置类)、Positive matches(表示已经生效的自动配置类)
三、Web开发 1、静态资源访问
  1. 静态资源目录

    1. 只要静态资源放在类路径下:当前类路径下的这四个包中–> /static—/public—/resources—/META-INF.resources 。可以直接通过项目根路径 /+静态资源名—>即可访问
    2. 原理:底层规定静态资源映射: @GetMapping("/goTo") public String TestRequestAttribute( HttpServletRequest request ){ request.setAttribute("msg","成功了....."); request.setAttribute("code","200"); // 请求转发到当前项目的路径上 return "forward:/success"; } @ResponseBody @GetMapping("/success") // 转发到该路径上 public Map GoToPage(@RequestAttribute("msg") String msg, @RequestAttribute("code") Integer code, HttpServletRequest request){ // 原生request中取出值 Object msg1 = request.getAttribute("msg"); Object code1 = request.getAttribute("code"); Map map = new HashMap<>(); // 拿到原生request中的值,存放到map中,并且展示出来 map.put("ReqMeth_msg",msg1); map.put("ReqMeth_code",code1); // 通过注解的方式拿到request中的值,存放到map中,并且展示出来 map.put("Annotation",msg); map.put("Annotation",code); return map; }
      测试首页的基本注解:
      
        传参
      • @PathVariable(路径变量)
      • @RequestHeader(获取请求头)
      • @RequestParam(获取请求参数)
      • @CookieValue(获取Cookie值)
      • @RequestBody(获取请求体)
      • @MatrixVariable(获取矩阵变量)
      • @RequestAttribute(获取Request域属性)
      ------------------------表单提交的内容---------------------------
      用户名:
      密   码:
      -------------------------矩阵变量--------------------------------
      1、问题

      ​ 在页面开发中,如果Cookie被禁用了,session里面的内容该怎么使用?

      ​ 答:①:在没禁用之前–>每次发起请求,cookie都会带上JsessionId,服务器按照JsessionId找到具体的session对象,然后调用session的get方法就能得到session中的内容

      ​ ②:被禁用之后–>因为JsessionId存放在cookie中,就无法通过cookie拿到JsessionId,拿不到JsessionId那么服务器就找不到对应的session对象,从而获取不到session对象中的属性值

      ​ ③:被禁用之后如何使用session中的内容—>可以通过矩阵变量的方式带上JsessionId(也称为 “路径重写” ),也就是把cookie的值通过矩阵变量的方式进行传递

      6、矩阵变量与路径帮助器
      1. 主要用于:cookie被禁用的情况下,通过get方式进行传参

      2. 原理:

        • SpringBoot对于路径的处理,通过UrlPathHelper进行解析,其中removeSemicolonContent(移除分号内容)属性支持矩阵变量,默认为true,默认是禁用矩阵变量的功能,必须手动开启,改为false
      3. 使用**@Bean注解往容器中添加组件WebMvcConfigurer或者实现WebMvcConfigurer接口,并且重写configurePathMatch**方法

      4. ------------------------实现接口的方法-------------------------
        @Override
            // configurePathMatch配置路径映射规则
            public void configurePathMatch(PathMatchConfigurer configurer) {
                UrlPathHelper pathHelper = new UrlPathHelper();
            	// 将true改为false:不移除':'分号后的内容,矩阵变量生效
                pathHelper.setRemoveSemicolonContent(false);
                // UrlPathHelper路径帮助器,默认是禁用掉矩阵变量的使用
                configurer.setUrlPathHelper(pathHelper);
            }
        -------------------------添加组件的方法------------------------
            @Bean
            public WebMvcConfigurer webMvcConfigurer(){
                return new WebMvcConfigurer() {
                    @Override
                    public void configurePathMatch(PathMatchConfigurer configurer) {
                        UrlPathHelper help = new UrlPathHelper();
                   // 设置成false:不移除';'分号后的内容,矩阵变量生效
                        help.setRemoveSemicolonContent(false);
                        configurer.setUrlPathHelper(help);
                    }
                };
            }
        
      5. 重点:在使用矩阵变量的时候,一定要绑定在路径变量上@GetMapping(“/cars/{path}”)

      // https://blog.csdn.net/cars/sell;low=34;brand=byd,audi,yd
          @GetMapping("/cars/{path}")
          public Map carSell(@MatrixVariable("low") Integer low,
                             @MatrixVariable("brand")List brand,
                             @PathVariable("path") String path){
              Map map = new HashMap<>();
              map.put("low",low);
              map.put("brand",brand);
              map.put("path",path);
              return map;
          }
          //url路径变量
          // https://blog.csdn.net/boss/1;age=20/2;age=10
          @GetMapping("/boss/{bossId}/{empId}")
          public Map boss(@MatrixVariable(value = "age",pathVar ="bossId" ) Integer bossAge,
                          @MatrixVariable(value = "age",pathVar ="empId" )Integer empAge){
              Map map = new HashMap<>();
              map.put("age",bossAge);
              map.put("age",empAge);
              return map;
          }
      
      one
      two(矩阵变量)
      @MatrixVariable(矩阵变量)/boss/{bossId}/{empId}
      
      7、参数处理原理 1、如何处理
      1. HandlerMapping中找到能处理请求的Handler,也就是Controller方法

      2. 为当前Handler找到一个适配器HandlerAdapter,而最终决定由哪个HandlerAdapter进行处理,是该方法作为判断,如果可以处理直接返回给DispathcerServlet下面的HandlerAdapter

        //DispatcherServlet -- doDispatch 首先进入该方法
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        
        
        // 执行目标方法 -->在该类中InvocableHandlerMethod        
        Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
        
        
        // 获取当前请求方法的参数值     
        Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
        ------//该方法进行判断当前请求需要哪个适配器进行处理------------
        public final boolean supports(Object handler) {
                return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
            }
        ------------//--------返回给该方法进行处理---------------------
             protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
                if (this.handlerAdapters != null) {
                    Iterator var2 = this.handlerAdapters.iterator();
        
                    while(var2.hasNext()) {
                        HandlerAdapter adapter = (HandlerAdapter)var2.next();
                        if (adapter.supports(handler)) {
                            return adapter;
                        }
                    }
                }
                throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
            }
        

        ​ 四种适配器:

        ​ 第0个:支持方法上标注@RequestMapping注解的(常用)

        ​ 第1个:支持函数式编程的(常用)

        2、参数解析器

        ​ 1)SpringMVC的目标方法能写多少种参数类型的参数,取决于底层的参数解析器接口中规定了多少种参数

        // 该方法中规定的27种参数解析器
        if (this.argumentResolvers != null) {   invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
                    }
        

      2)参数解析器接口中的方法判断

      public interface HandlerMethodArgumentResolver {
          // 判断当前是否支持需要处理的参数
          boolean supportsParameter(MethodParameter var1);
      	// 支持则调用该方法进行解析
          @Nullable
          Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
      }
      

      ​ 3)参数返回值处理器

      if (this.returnValueHandlers != null) {
      // 规定了15种处理器
      invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
                  }
      

      3、如何确定目标方法每一个参数的值

      ​ 1)底层原理

      //==========代码出处:--->InvocableHandlerMethod<----------------
       	protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
          // 先获取到所有方法的参数声明
              MethodParameter[] parameters = this.getMethodParameters();
          // 判断参数是否为空,没有参数的话,直接返回
              if (ObjectUtils.isEmpty(parameters)) {
                  return EMPTY_ARGS;
              } else {
          // 通过Object数组对参数进行存储,长度随着参数个数变化
                  Object[] args = new Object[parameters.length];
                  // 对拿到的参数进行遍历
                  for(int i = 0; i < parameters.length; ++i) {
                      // 得到第一个遍历的参数
                      MethodParameter parameter = parameters[i];  
                      
       // 初始化参数,得到参数的名称
                      parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                      // 赋值
       args[i] = findProvidedArgument(parameter, providedArgs);
                      if (args[i] == null) {
              // 重点:判断当前解析器是否支持该参数类型
      if (!this.resolvers.supportsParameter(parameter)) {
                              throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                          }
                          try {
                              args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                          } catch (Exception var10) {
                              if (logger.isDebugEnabled()) {
                                  String exMsg = var10.getMessage();
                                  if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {    logger.debug(formatArgumentError(parameter, exMsg));
                                  }
                              }
                              throw var10;
                          }
                      }
                  }
                  return args;
              }
          }
      ----------------//重点:判断当前解析器是否支持该参数类型---------
           @Nullable
          private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
              HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
              if (result == null) {
           // 将参数赋值给迭代器,然后依次遍历27个参数解析器,寻找是否有解析器能够解析传入的参数
                  Iterator var3 = this.argumentResolvers.iterator();
                  while(var3.hasNext()) {
                      HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
                      if (resolver.supportsParameter(parameter)) {
                          result = resolver;
            // 通过遍历,找到相应的参数解析器之后,放入缓存中,方便下次取,不用再从新遍历
                          this.argumentResolverCache.put(parameter, resolver);
                          break;
                      }
                  }
              }
              return result;
          }
      
      
      4、Servlet API

      WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId

      ServletRequestMethodArgumentResolver 以上的部分参数

      能够处理的API

      @Override
      	public boolean supportsParameter(MethodParameter parameter) {
      		Class paramType = parameter.getParameterType();
      		return (WebRequest.class.isAssignableFrom(paramType) ||
      				ServletRequest.class.isAssignableFrom(paramType) ||
      				MultipartRequest.class.isAssignableFrom(paramType) ||
      				HttpSession.class.isAssignableFrom(paramType) ||
      				(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
      				Principal.class.isAssignableFrom(paramType) ||
      				InputStream.class.isAssignableFrom(paramType) ||
      				Reader.class.isAssignableFrom(paramType) ||
      				HttpMethod.class == paramType ||
      				Locale.class == paramType ||
      				TimeZone.class == paramType ||
      				ZoneId.class == paramType);
      	}
      
      5、复杂参数

      Map、**Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、**Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder

      Map map,  Model model, HttpServletRequest request 以上三个参数都是可以给request域中放数据,
          在通过取出
      request.getAttribute();
      

      Map、Model类型的参数,会返回 mavContainer.getModel();—> BindingAwareModelMap 是Model 也是Map

      mavContainer.getModel(); 获取到值的

      8、自定义类型(封装POJO)参数处理原理

      ServletModelAttributeMethodProcessor:

      ---------------------------判断----------------------------------
       private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
              HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
              if (result == null) {
                  Iterator var3 = this.argumentResolvers.iterator();
      
                  while(var3.hasNext()) {
                      HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
               // 判断解析器支持哪些参数
                      if (resolver.supportsParameter(parameter)) {
                          result = resolver;
                          this.argumentResolverCache.put(parameter, resolver);
                          break;
                      }
                  }
              }
      
              return result;
      }
      ------------------------进入方法--------------------------------
          public boolean supportsParameter(MethodParameter parameter) {
          // 首先判断改参数是否有@ModelAttribute注解
      return parameter.hasParameterAnnotation(ModelAttribute.class) ||
          // 判断这个注解是不是必须的"require = true/false"
      this.annotationNotRequired &&     
          // 判断是不是简单属性,“!:表示非简单属性” 返回true表示不是简单类型
          !BeanUtils.isSimpleProperty(parameter.getParameterType());
          }
      ------------------------进入方法:简单类型判断--------------------
          public static boolean isSimpleValueType(Class type) {
              return Void.class != type && Void.TYPE != type && 		(ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type);
          }
      --------------------------------核心----------------------------
            @Nullable
          public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
              Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
              Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
              String name = ModelFactory.getNameForParameter(parameter);
              ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
              if (ann != null) {
                  mavContainer.setBinding(name, ann.binding());
              }
      
              Object attribute = null;
              BindingResult bindingResult = null;
              if (mavContainer.containsAttribute(name)) {
                  attribute = mavContainer.getModel().get(name);
              } else {
                  try {
                      // 先创建一个空的实例对象,然后通过 WebDataBinder绑定器进行绑定
                      attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
                  } catch (BindException var10) {
                      if (this.isBindExceptionRequired(parameter)) {
                          throw var10;
                      }
      
                      if (parameter.getParameterType() == Optional.class) {
                          attribute = Optional.empty();
                      } else {
                          attribute = var10.getTarget();
                      }
      
                      bindingResult = var10.getBindingResult();
                  }
              }
      
              if (bindingResult == null) {
       // web数据绑定器,将请求参数的值绑定到指定的JavaBean中(也就是attribute中,而attribute在绑定数据之前就已经创建了一个空的attribute实例)。封装到binder里,而binder还有conversionService,里面有converters = 125个转换器。
                  // 为什么会有125个转换器呢?
                  // 因为请求是HTTP(超文本传输协议),认为万物皆文本,通过文本传输数字时,必须转换成java形式的Interget,这个时候就用到其中的转换器
                  WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
                  if (binder.getTarget() != null) {
                      if (!mavContainer.isBindingDisabled(name)) {
                          // 该方法如何进行绑定在下面
                          this.bindRequestParameters(binder, webRequest);
                      }
      
                      this.validateIfApplicable(binder, parameter);
                      if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
                          throw new BindException(binder.getBindingResult());
                      }
                  }
      
                  if (!parameter.getParameterType().isInstance(attribute)) {
                      attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
                  }
      
                  bindingResult = binder.getBindingResult();
              }
      
              Map bindingResultModel = bindingResult.getModel();
              mavContainer.removeAttributes(bindingResultModel);
              mavContainer.addAllAttributes(bindingResultModel);
              return attribute;
          }
      ------------------------如何绑定的核心方法------ -----------------
           protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
          // 1、先获取原生的request请求
              ServletRequest servletRequest = (ServletRequest)request.getNativeRequest(ServletRequest.class);
          // 2、判断请求不为空
              Assert.state(servletRequest != null, "No ServletRequest");
          // 3、拿到(WebDataBinder)web数据绑定器,转换成ServletRequestDataBinder,拿到request中的数据
              ServletRequestDataBinder servletBinder = (ServletRequestDataBinder)binder;
          // 4、再调用bind方法,将原生的request传进来进行绑定
              servletBinder.bind(servletRequest);
          }
      

      核心原理:WebDataBinder(web数据绑定器)会最终把请求中的所有数据利用这125个转换器进行转换,再通过反射绑定到空的JavaBean上

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/826972.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号