Spring源码06 - @Controller注解

Spring源码06 - @Controller注解

Spring框架是底层是如何实现的通过使用@Controller注解就简单的完成了http请求的接收与处理

@RestController的底层是@Controller + @ResponseBody

一:Controller注解

@Target({ElementType.TYPE})
@Component
public @interface Controller {
   String value() default "";
}

发现Controller注解打上了Component的注解,这样Spring做类扫描的时候,发现了@Controller标记的类也会当作Bean解析并注册到Spring容器。

我们可以看到Spring的类扫描器,第一个就注册了Component注解的扫描

//org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
protected void registerDefaultFilters() {
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
}

这样Spring容器启动完成之后,bean容器中就有了被Controller注解标记的bean实例了。

到这里只是单纯的把Controller标注的类实例化注册到Spring容器,和Http请求接收处理没半毛钱关系,那么他们是怎么关联起来的呢?

二:Spring解析Controller方法

这个时候Springmvc组件中的另外一个组件就闪亮登场了

RequestMappingHandlerMapping

RequestMappingHandlerMapping 看这个名就可以知道他的意思,请求映射处理映射器。

这里就是重点了,该类间接实现了InitializingBean方法,bean初始化后执行回调afterPropertiesSet方法,里面调用initHandlerMethods方法进行初始化handlermapping。

// 判断一个类是否是处理器(即是否是Controller)
protected boolean isHandler(Class<?> beanType) {
   // 检查类是否有@Controller注解或@RequestMapping注解
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

// 初始化处理器方法
protected void initHandlerMethods() {
   // 从应用上下文中获取所有bean的名称(Object.class表示获取所有类型的bean)
   String[] beanNames = applicationContext().getBeanNamesForType(Object.class);

   // 遍历所有bean名称
   for (String beanName : beanNames) {
         // 获取bean的类型
         Class<?> beanType = obtainApplicationContext().getType(beanName);
         // 检查是否是处理器类(有Controller或RequestMapping注解)
         if (beanType != null && isHandler(beanType)) {
            // 如果是处理器,则检测其中的处理器方法
            detectHandlerMethods(beanName);
         }
   }
   // 所有处理器方法初始化完成后调用
   handlerMethodsInitialized(getHandlerMethods());
}
  1. 获取 Spring 容器中所有 bean 的名称
  2. 遍历每个 bean,检查其类型
  3. 判断是否是处理器(通过 @Controller@RequestMapping 注解)
  4. 如果是处理器,则进一步解析其中的请求映射方法 -> detectHandlerMethods
  5. 所有处理器初始化完成后进行回调

这里把标注了Controller注解的实例全部找到了,然后调用detectHandlerMethods方法

检测handler方法,也就是解析Controller标注类的方法。

// 注册表,用于存储所有处理器方法的映射关系
// Key: 映射信息(通常是路径和HTTP方法的组合)
// Value: MappingRegistration对象,包含映射信息和对应的Method对象
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

// 检测给定处理器中的处理器方法
protected void detectHandlerMethods(final Object handler) {
   // 获取处理器的类型
   // 如果handler是String类型(bean名称),则通过应用上下文获取其类型
   // 否则直接获取handler的Class对象
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   // 确保类型不为空
   if (handlerType != null) {
      // 获取用户定义的类(处理可能的CGLIB代理情况)
      final Class<?> userType = ClassUtils.getUserClass(handlerType);
      
      // 使用MethodIntrospector查找类中所有需要映射的方法
      // selectMethods方法会扫描类及其父类中的所有方法
      // getMappingForMethod回调用于确定每个方法是否有映射信息
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
      
      // 遍历找到的所有方法及其映射信息
      methods.forEach((method, mapping) -> {
         // 将映射信息和方法注册到registry中
         this.registry.put(mapping, new MappingRegistration<>(mapping, method));
      });
   }
}

到这里为止,Spring将Controller标注的类和类方法已经解析完成。

现在再来看RequestMappingHandlerMapping这个类的作用,他就是用来注册所有Controller类的方法。

三:Spring调用Controller方法

接着还有一个重要的组件RequestMappingHandlerAdapter

它就是用来调用我们写的Controller方法,完成请求处理的流程。

@Override
public boolean supports(Object handler) {
   return handler instanceof HandlerMethod;
}

protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   //请求check
   checkRequest(request);
   //调用handler方法
   mav = invokeHandlerMethod(request, response, handlerMethod);
   //返回
   return mav;
}

四:DispatcherServlet调度Controller方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
         // 从注册表查找handler
         HandlerExecutionChain mappedHandler = getHandler(request);
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
         // 底层调用Controller
         ModelAndView m = ha.handle(processedRequest, response, mappedHandler.getHandler());
         // 处理请求结果
         processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

dispatcherServlet -> 请求 -> HandlerMethod -> 转换 -> HandlerAdapter -> doHandler

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值