其实Spring比较厉害,把能自定义的地方全都精心的做了设计。比如要实现这个自定义注解实现RequestMapping注解的功能。只需要很少的代码就能完成这个功能。这里强调一下,真的是很少的代码哦,并且不会引用第三方的类库。全都是基于Spring MVC的。开始吧!!
0,第一步自然是定义一个注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMappingTest {
String value();
}
1,其次需要继承AbstractHandlerMethodMapping并覆写相应的方法。这里被覆写的方法便是解析规则。整套解析流程已经定义好了。参见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) {
Set<String> patterns = mapping.getPatternsCondition().getPatterns();
for (String pattern : patterns) {
if (pattern.equals(request.getServletPath())) {
return mapping;
}
}
return null;
}
@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());
}