自定义注解实现@RequestMapping路由功能

其实Spring比较厉害,把能自定义的地方全都精心的做了设计。比如要实现这个自定义注解实现RequestMapping注解的功能。只需要很少的代码就能完成这个功能。这里强调一下,真的是很少的代码哦,并且不会引用第三方的类库。全都是基于Spring MVC的。开始吧!!

0,第一步自然是定义一个注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMappingTest {
    String value();
}

1,其次需要继承RequestMappingHandlerMapping并覆写相应的方法。这里被覆写的方法便是解析规则。整套解析流程已经定义好了。参见org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet

public class HandlerMappingHandlerTest extends AbstractHandlerMethodMapping<RequestMappingInfo> {

    @Override
    protected boolean isHandler(Class beanType) {
        return beanType.getDeclaredAnnotation(RestController.class) != null || beanType.getDeclaredAnnotation(Controller.class) != null;//判断一个Handler是不是controller
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);// 方法上的注解
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);//类上的注解
            if (typeInfo != null) {
                info = typeInfo.combine(info);//组合
            }
        }
        return info;
    }

    @Override
    protected Set<String> getMappingPathPatterns(RequestMappingInfo mapping) {
        return mapping.getPatternsCondition().getPatterns();
    }

    @Override
    protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, HttpServletRequest request) {
        return mapping;//这里可以优化
    }

    @Override
    protected Comparator<RequestMappingInfo> getMappingComparator(HttpServletRequest request) {
        return (info1, info2) -> info1.compareTo(info2, request);
    }

    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMappingTest annotation = AnnotatedElementUtils.findMergedAnnotation(element, RequestMappingTest.class);
        if (annotation == null) return null;

        RequestMappingInfo.Builder builder = RequestMappingInfo
                .paths(annotation.value());
        return builder.build();
    }

    @Override
    public void afterPropertiesSet() {
        super.setOrder(-1);//这里是为了优先级要超过RequestResponseBodyMethodProcessor
        super.afterPropertiesSet();
    }
}

2,要注册为一个Bean,这里重要的是初始化过程。注册为一个Bean实际上就是一个处理器。详见org.springframework.web.servlet.DispatcherServlet#doDispatch这里会调用到。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public HandlerMapping handlerMappingTest() {
        return new HandlerMappingHandlerTest();
    }
}

3,然后就没有了,开始测试。

@RestController
@RequestMappingTest("/1")
public class ControllerMappingTest {

    @RequestMappingTest("/test1")
    public Object test1(@ModelAttribute A a, @ModelAttribute B b) {
        System.out.println(a.getId());
        System.out.println(b.getId());
        return CResponse.of(true);
    }
}

public class CResponse<T> {
    private Integer code;
    private String message;
    private T data;

    public CResponse(T data) {
        this.data = data;
        this.code = 200;
    }

    public CResponse(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static <T> CResponse of(T data) {
        return new CResponse<>(data);
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

postman: http://localhost:8080/test?id=1

4,是不是非常简单,虽然看起来很简单,但是实际上Spring是做了许多工作的。

比如每一个Bean在属性设置完后,会对所有的Controller实行这样的规则检查,这个规则就是i我们继承于

AbstractHandlerMethodMapping<RequestMappingInfo> 

。并覆写的方法。这些方法便是Spring留给我们自定义的。但是整个解析流程Spring已经帮我们做好了。(ps:Spring的设计人员是真的强!!!)

AbstractHandlerMethodMapping在属性设置完成后,会扫描所有的Bean,从中找出controller,并尝试将规则应用到这些controller中,并且将其注册到HandlerMapping中,以供DispatchServlet调用。

protected void initHandlerMethods() {
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
            obtainApplicationContext().getBeanNamesForType(Object.class));//获取所有的Bean

    for (String beanName : beanNames) {
        Class<?> beanType = obtainApplicationContext().getType(beanName);
        if (beanType != null && isHandler(beanType)) {// 判断是否是controller
            detectHandlerMethods(beanName);//注册方法
        }
    }
}
// 这里是DispatchServlet的最主要的方法,没有之一
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Determine handler for the current request.
        HandlerExecutionChain mappedHandler = getHandler(processedRequest);// 这里会便利所有的HandlerMapping(我们自定义的HandlerMappingHandlerTest就会出现在这里,成为规则), 然后构建执行链

        // Determine handler adapter for the current request.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 这里也可以自定义,默认是RequestMappingHandlerAdapter

        // Actually invoke the handler.
        ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }

demo链接

发布了29 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/u012803274/article/details/104723740
今日推荐